superx-cli 0.3.0 → 0.5.0

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.
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: superx
3
- description: SuperX is a Twitter/X growth tool. Use it to read an account's published posts with engagement metrics, pull account analytics (impressions, likes, replies, follower change), find the people who engage with the account most, review reply history in both directions (sent and received), manage contact lists, create and manage signal agents (automated lead finders) and review the leads they discover, search a library of 50M+ high-performing posts for inspiration, read the Engage feed posts a saved feed surfaces for review, create, edit, tag, or schedule draft posts and threads (with image attachments), write, schedule, publish, and generate AI covers for long-form X Articles, and read or update the account's Context settings (profile description, interests, SuperX rules, reply settings, favorite creators, style guide, products) that steer SuperX's AI writing, all through the SuperX API.
3
+ description: SuperX is a Twitter/X growth tool. Use it to read an account's published posts with engagement metrics, pull account analytics (impressions, likes, replies, follower change), find the people who engage with the account most, review reply history in both directions (sent and received), manage contact lists, create and manage signal agents (automated lead finders), add or remove the signals they watch, and review the leads they discover, marking each one fit or not fit, search a library of 50M+ high-performing posts for inspiration, create, edit, and delete saved Engage feeds and read the posts they surface for review, create, edit, tag, or schedule draft posts and threads (with image attachments), write, schedule, publish, and generate AI covers for long-form X Articles (in one of the account's saved cover styles), and read or update the account's Context settings (profile description, interests, SuperX rules, reply settings, favorite creators, style guide, products) that steer SuperX's AI writing, all through the SuperX API.
4
4
  homepage: https://docs.superx.so
5
5
  metadata: {"openclaw":{"emoji":"🚀","requires":{"bins":["superx"],"env":[]}}}
6
6
  ---
@@ -30,9 +30,9 @@ official website: https://superx.so
30
30
 
31
31
  **Rule 1: Run `superx status` before anything else.** Every other command fails without valid credentials. If the `superx` binary is missing, install it with `npm install -g superx-cli`. If not authenticated, either run `superx login` (interactive) or set `export SUPERX_API_KEY=sxk_...` (CI and non-interactive sessions). Keys are created at https://app.superx.so/account?tab=api.
32
32
 
33
- **Rule 2: Read PLAYBOOK.md before creating any content.** This repo ships a growth strategy guide (`PLAYBOOK.md`, also inside the installed npm package). It tells you WHAT to post, WHEN, and WHY: the action hierarchy, out-of-network discovery, the engagement loop, and the failure modes that kill reach. The CLI gives you data and actions; the playbook gives you judgment. Do not schedule content without it.
33
+ **Rule 2: Read PLAYBOOK.md before creating any content.** This repo ships a growth strategy guide (`PLAYBOOK.md`, also inside the installed npm package). It tells you WHAT to post, WHEN, and WHY: the action hierarchy, out-of-network discovery, the engagement loop, and the failure modes that kill reach. The CLI gives you data and actions; the playbook gives you judgment. Do not schedule content without it. For a goal-shaped task ("give me my weekly recap", "DM the people who replied to this post"), read `PLAYBOOKS.md` too: it holds the 29 named recipes with their exact command chains, MCP tool names and stopping points.
34
34
 
35
- **Rule 3: Know the write constraints.** `scheduled:create` without `--at` creates a DRAFT (nothing publishes). With `--at` it schedules for that time. `scheduled:update` changes only the flags you pass, and a new `--at` alone never schedules a draft; add `--status scheduled` to promote. Writes work on your main account or any linked account (pass the same `--account` you used to read it); accounts shared with you by other people are read-only, and tags are workspace-wide. Images attach via `media:upload` then `--media` (JPG/PNG/WEBP up to 5MB, GIF up to 15MB; max 4 images or 1 GIF per post); video is not supported. Timestamps MUST be UTC ISO-8601 with an explicit `Z` or offset; naive timestamps are rejected with 400. `articles:publish` posts a long-form article to X IMMEDIATELY and irreversibly; treat it like hitting Publish in public and get human confirmation unless the user already gave it.
35
+ **Rule 3: Know the write constraints.** `scheduled:create` without `--at` creates a DRAFT (nothing publishes). With `--at` it schedules for that time. `scheduled:update` changes only the flags you pass, and a new `--at` alone never schedules a draft; add `--status scheduled` to promote. Writes work on your main account or any linked account (pass the same `--account` you used to read it); accounts shared with you by other people are read-only, and tags are workspace-wide. Images attach via `media:upload` then `--media` (JPG/PNG/WEBP up to 5MB, GIF up to 15MB; max 4 images or 1 GIF per post); video is not supported. Timestamps MUST be UTC ISO-8601 with an explicit `Z` or offset; naive timestamps are rejected with 400. `posts:publish` and `articles:publish` post to X IMMEDIATELY and irreversibly; treat them like hitting Publish in public and get human confirmation of the exact text unless the user already gave it. `posts:publish` also requires `--idempotency-key`, which you reuse verbatim on any retry. `posts:draft` writes post text in the user's voice and saves NOTHING: show the drafts, let the user pick and edit one, then pass the final text to `scheduled:create` yourself; it costs AI credits per draft, so ask for the count the user actually wants. `--voice mine` is the voice of the `--account` you pass (its own posts and style guide); shared accounts are refused.
36
36
 
37
37
  ---
38
38
 
@@ -51,7 +51,7 @@ echo "$POSTS" | jq '.data[].text'
51
51
 
52
52
  ## Core Workflow
53
53
 
54
- 1. **Check auth**: `superx status` (verifies the key and shows plan + rate-limit state)
54
+ 1. **Check auth**: `superx status` (verifies the key and shows plan, AI credit pool, and rate-limit state)
55
55
  2. **Discover accounts**: `superx accounts` (main account first; note ids for `--account`)
56
56
  3. **Read the data**: top posts, analytics, most engaged contacts
57
57
  4. **Read PLAYBOOK.md**, then draft content informed by what already works for this account
@@ -89,7 +89,7 @@ superx scheduled:list --status draft,scheduled
89
89
  ```bash
90
90
  superx login # Guided: prints the key page URL, prompts for a paste
91
91
  superx login --key "sxk_..." # Non-interactive
92
- superx status # Verify credentials; shows plan, key scopes, rate limits
92
+ superx status # Verify credentials; shows plan, credits, key scopes, rate limits
93
93
  superx logout # Delete ~/.superx/credentials.json
94
94
  export SUPERX_API_KEY=sxk_... # Env alternative (credentials file wins when both exist)
95
95
  ```
@@ -135,6 +135,40 @@ superx inspiration:search "AI tools" --min-likes 500 --min-followers 1000 --max-
135
135
  - `outlier_score` on each result = how far the post outperformed the norm for its author's follower tier. Sorting by `outlier` surfaces content that won on substance, not audience size.
136
136
  - Results are relevance-ranked, strongest matches first. Weak and promotional matches are filtered out, so a page may return fewer than `--limit` posts.
137
137
 
138
+ ### Live X lookups
139
+
140
+ ```bash
141
+ superx x:post https://x.com/levelsio/status/1938765432109876543 # one public post, live
142
+ superx x:post 1938765432109876543 --quotes # + a page of quote posts
143
+ superx x:replies 1938765432109876543 --limit 20 # best-liked direct replies
144
+ superx x:user @levelsio # one public profile, live
145
+ superx x:user-posts levelsio --limit 20 --no-reposts # their latest posts
146
+ ```
147
+
148
+ - These read X **right now**, not SuperX's stored data. Use them for a post or account the user names; use `posts:list` / `contacts:*` for the user's own SuperX data.
149
+ - Cost: the tighter **enrichment** allowance, 1 unit each, **3** for `x:replies` (it walks up to 3 pages), 2 for `x:post --quotes` and 2 for an `x:user-posts` handle SuperX has never seen (`profile_resolved_locally: false` reports that). A multi-unit call is all-or-nothing, never half-charged.
150
+ - On top of that they share an allowance of **300 live lookups per day** with Ask SuperX inside the app. Over it: `429 lookup_quota_exceeded` with `retry_after`, `limit` and `reset_at`, resetting at midnight UTC. That gate fails CLOSED, so the same code appears when SuperX cannot verify the count. Do not retry in a loop; tell the user.
151
+ - Results are cached server-side for about **15 minutes**. A repeat still costs its enrichment units but does not touch the 300/day allowance.
152
+ - `x:replies` is a **sample**: the best-liked replies from up to 3 relevance-ranked pages (about 60 candidates), never every reply and never chronological. For everyone who replied to a post, use the audience collections (`datasets:list`) built in the app. It also does NOT hide the account owner's own replies, unlike the same feature in the app.
153
+ - `x:post` 404s `post_not_found` for a deleted, protected or wrong id. The upstream read reports a missing post and a failed read identically, so retry once before telling the user a post is gone. `x:user` / `x:user-posts` 404 `user_not_found` for a suspended, renamed or misspelled handle.
154
+ - Owner-scoped: none of these take `--account`. Nothing about a public lookup is per-X-account.
155
+
156
+ ### Inspiration media (cross-platform)
157
+
158
+ ```bash
159
+ superx inspiration:media "founder morning routine" --limit 10
160
+ superx inspiration:media --platforms youtube,instagram --media-type video
161
+ superx inspiration:media # browse the newest
162
+ ```
163
+
164
+ - Searches the media index behind the app's Inspiration > Media tab: short-form video and image posts from x, instagram, youtube, threads, reddit and linkedin, with captions, a summary and engagement counts.
165
+ - **No media file URLs.** There is no thumbnail or video link in the response; `source_url` opens the original post on its own platform, so link the user there rather than trying to embed the media.
166
+ - With **no query** it browses the newest media instead of searching. `meta.mode` says which ran, and only `search` results carry a `score`. Unlike the app there is **no personalisation** here.
167
+ - Costs no enrichment. Its own caps are a burst of 20 (refilling one every 3 seconds) and 500 FRESH searches a day; repeats of a recent identical search come from a cache and do not count.
168
+ - **No pagination.** One query returns at most 120 items and `--limit` only trims that, so ask for `--limit 120` and filter locally rather than calling it again for "the next page".
169
+ - `--content-type` is a **free-text label as stored in the index**, with no list to choose from. A label the index does not use returns zero items and still burns one of the 500 daily searches, so leave it off unless the user named one.
170
+ - Use it for visual format and hook research, never to copy.
171
+
138
172
  ### Contacts (who engages with you)
139
173
 
140
174
  ```bash
@@ -145,6 +179,21 @@ superx contacts:replies <contact-id> --sort recent # One person's reply history
145
179
 
146
180
  Sort options: `contacts:list` takes `engagement|replies|reposts`; `contacts:replies` takes `recent|most_liked`.
147
181
 
182
+ ```bash
183
+ superx contacts:get <x-user-id> # Profile, follower counts, verified state, lists they are in (known contacts only)
184
+ superx contacts:get <x-user-id> --refresh # Refresh a stale profile from X (costs an enrichment unit)
185
+ superx contacts:notes <x-user-id> # Your private notes about them, newest first
186
+ superx contacts:notes:add <x-user-id> --body "Wants a demo in September"
187
+ superx contacts:notes:update <x-user-id> <note-id> --body "Demo booked for 12 Sept"
188
+ superx contacts:notes:delete <x-user-id> <note-id>
189
+ ```
190
+
191
+ - The id everywhere here is a NUMERIC X user id, from `contacts:list`, `lists:members` or `signals:leads`. `contacts:get` returns the stored profile plus each list the person is in, with the `member_id` that `lists:remove-member` takes.
192
+ - KNOWN CONTACTS ONLY: `contacts:get` and `contacts:notes:add` resolve people the account actually knows, meaning anyone who has replied to or reposted its posts, a member of one of its contact lists (manual or system), or a scored signal lead. Any other id returns 404 `contact_not_found`, even one SuperX holds a profile for. This is NOT a general X profile lookup: take ids from `contacts:list`, `lists:members` or `signals:leads` rather than typing one in.
193
+ - `--refresh` is the only path that calls X. Leave it off unless the follower counts have to be current: it counts against the tighter enrichment limit, and the default read is free of it.
194
+ - Notes live inside SuperX and are NEVER posted anywhere. Use them for context you want on the next conversation. A note written through the CLI is attributed to the account you wrote as.
195
+ - Note writes need a key with the write scope; shared accounts are read-only.
196
+
148
197
  ### Contact lists
149
198
 
150
199
  ```bash
@@ -155,10 +204,88 @@ superx lists:remove-member <list-id> <member-id> # member-id from lists:memb
155
204
  ```
156
205
 
157
206
  - Lists are the saved people-collections from the SuperX app. Use them to track prospects, customers, or people worth engaging.
158
- - System lists (Followers, Following, Repliers, Reposters) appear in `lists:list` with `is_system: true` but are read-only and their members are NOT available through the API.
207
+ - System lists (Followers, Following, Repliers, Reposters) appear in `lists:list` with `is_system: true` and a real `member_count`, but they are read-only and `lists:members` will not serve them: read their people with `audience:list <kind>` instead.
159
208
  - Adding someone already in a list is harmless: the existing member returns with `"duplicate": true` and nothing changes.
160
209
  - Member writes work on your main or linked accounts (`--account`) and need a key with the write scope; shared accounts are read-only.
161
210
 
211
+ ```bash
212
+ superx lists:create --name "Founder prospects" # Names are NOT unique; check lists:list first
213
+ superx lists:rename <list-id> --name "Q4 prospects"
214
+ superx lists:delete <list-id> # Deletes the list and its membership; the people stay
215
+ superx lists:add-members <list-id> --x-user-ids 44196397,944883311 # up to 500 per call
216
+ superx lists:remove-members <list-id> --member-ids m1abc,m2def # up to 500 per call
217
+ ```
218
+
219
+ - `lists:add-members` does NO live lookup: it uses profiles SuperX already stores, which is why it costs one write and no enrichment. Ids SuperX has never seen come back in `not_found` and are NOT added. Add those one at a time with `lists:add-member --handle`, which does resolve live.
220
+ - Re-adding someone already in the list is counted in `duplicates`, never an error. `lists:remove-members` skips ids that are not in the list, so `deleted` can be lower than what you sent.
221
+ - `lists:delete` also stops any signal agent depositing into that list until the agent is repointed in the SuperX app. Confirm with the user first.
222
+
223
+ ### Audience (followers, following, repliers, reposters)
224
+
225
+ ```bash
226
+ superx audience:list followers --limit 100 # newest followers first
227
+ superx audience:list following
228
+ superx audience:list repliers # people who replied in the last 90 days
229
+ superx audience:list reposters
230
+ superx audience:list followers --cursor "<next_cursor>" # the next page
231
+ ```
232
+
233
+ - These are the four SYSTEM people-lists in the app's Contacts tab. `lists:members` does not serve them; this is where they are read.
234
+ - Paging is by **cursor**, not page number. Take `pagination.next_cursor` from one call and pass it as `--cursor` to the next; `has_more: false` means you are at the end. Do not try `--page`.
235
+ - There is no `total`. `meta.synced_count` is the size of the whole list, so quote that rather than counting rows. It may exceed the rows a full walk returns, because edges that were later removed are still counted.
236
+ - `meta.status` is the sync state (`missing`, `pending`, `running`, `complete`, `paused`): anything but `complete` means SuperX is still filling the list in, so say so rather than presenting a partial list as the whole audience.
237
+ - On `followers` / `following`, `meta.is_capped: true` means the account is deeper than the plan's `backfill_cap` and the list is the most recent slice, not everyone.
238
+ - `repliers` and `reposters` are a rolling 90-day window (`meta.window_days`): someone whose last reply ages past 90 days drops out and comes back on their next one.
239
+ - `engaged_count` is replies + reposts in the last 90 days on the follow lists, and this list's own action count on the other two. `icp_score` and `icp_rationale` are always null here (scoring belongs to signal-agent leads).
240
+ - Costs no enrichment units, and reads like any other GET.
241
+
242
+ ### Mentions (who is talking to you right now)
243
+
244
+ ```bash
245
+ superx engage:mentions # newest mentions, with the post each replies to
246
+ superx engage:mentions --sort top # most engaged first
247
+ superx engage:mentions --include-replied true # keep ones you already answered, flagged replied
248
+ superx engage:mentions --cursor "<next_cursor>" # the next page
249
+ ```
250
+
251
+ - Reads X **live**, so it is the up-to-the-minute view of what people are saying to the user, unlike `replies:received` which reads what SuperX has stored.
252
+ - One call costs **3 of the daily feed fetches** (the same allowance `engage:posts` draws on): read a page and work from it rather than polling.
253
+ - `mention_type` is `reply` for a direct reply to one of the user's posts and `mention` for anything else (standalone @-mention, chain, or being tagged in someone else's reply). `parent_post` carries the post being replied to, with one further level of ancestry.
254
+ - By default, mentions the user already replied to on X are left out. `--include-replied true` keeps them with `replied: true`.
255
+ - The app's Mentions tab also hides posts the user skipped or blocked there. That is an app preference and is NOT applied here, so the API list can be longer than what they see in the app.
256
+ - READ-ONLY, like Engage: there is no reply command. Draft suggestions for the user and let them send.
257
+
258
+ ### Datasets (Ask SuperX collections)
259
+
260
+ ```bash
261
+ superx datasets:list # collections built in the app, newest first
262
+ superx datasets:get <dataset-id> # status, counts, coverage sentence
263
+ superx datasets:rows <dataset-id> --limit 50 # a page of rows, exactly as collected
264
+ superx datasets:export <dataset-id> # writes superx-dataset-<title>-<date>.csv here
265
+ superx datasets:export <dataset-id> --out - # stream the CSV to stdout instead
266
+ superx datasets:add-to-list <dataset-id> --list-id <list-id> # copy its people into a list
267
+
268
+ # Build a new one (write scope)
269
+ superx datasets:collect --source repliers --target https://x.com/user/status/123 --wait
270
+ superx datasets:collect --source list_members --target https://x.com/i/lists/1234567890
271
+ superx datasets:collect --source my_posts --since-days 90 --sort likes
272
+ superx datasets:collect --source reposters --target 1234567890 --min-followers 500 --require-can-dm
273
+
274
+ # Narrow a dataset by what each person wrote (creates a NEW dataset)
275
+ superx datasets:refine <dataset-id> --criterion "supportive or neutral, not hostile" --sort followers --wait
276
+ ```
277
+
278
+ - Datasets are audience collections: the repliers, quoters or reposters of a post, the members of an X list, the user's own posts or replies, or a set of research briefs. `datasets:collect` builds one from here, `datasets:research` builds the briefs kind (see Lead search and outreach below), and the ones Ask SuperX builds in the app show up in the same list.
279
+ - `datasets:collect` may not be done when it returns. A big collection, or one whose size cannot be established up front, answers `status: "collecting"` with zero rows and keeps running in the background: pass `--wait` to poll until it is ready, or poll `datasets:get` yourself. NEVER quote a row count from a `collecting` result.
280
+ - Each collection costs one of **10 a day** for the account, shared with the collections Ask SuperX runs in the app (429 `collection_quota_exceeded`), plus enrichment for the pages it walks. `--source my_posts` / `my_replies` read the local post library: no enrichment, always synchronous, and the profile filters do not apply to them (the `note` says so).
281
+ - Only ONE background collection runs per account at a time: a second one returns 409 `collection_in_progress`. If nothing matched the filters no dataset is created: the answer is `data: null` with a `note`.
282
+ - They are kept for **30 days**. After that the id 404s.
283
+ - `status` is `collecting`, `ready` or `failed`. Only a `ready` dataset can be paged, exported or added to a list; the others return `409 dataset_not_ready`.
284
+ - Export is **CSV only**. XLSX downloads stay in the SuperX app.
285
+ - `has_people: false` marks an own-content dataset (the user's posts or replies): there is nobody in it to add to a contact list.
286
+ - Dataset ids come from `datasets:list`; the tool that created one also reports its id in the app.
287
+ - `datasets:refine` filters a dataset by WHAT EACH PERSON WROTE and writes the kept rows to a NEW dataset; the source is untouched. It only works on datasets whose rows carry text (repliers, quoters) - anything else is a 400. Rows the classifier cannot judge are KEPT and counted as `unclear`, so report those honestly rather than claiming clean curation. It creates a dataset, so it counts against the SAME 10 collections a day, and it costs AI credits. Over 100 rows with text it answers `202 collecting`: pass `--wait` or poll `datasets:get`.
288
+
162
289
  ### Engage (feed posts to reply to)
163
290
 
164
291
  ```bash
@@ -167,9 +294,20 @@ superx engage:posts <feed-id> --limit 50 # one big page of candidate
167
294
  superx engage:posts <feed-id> --mode latest --fresh true # newest, skipping the cache
168
295
  superx engage:posts <feed-id> --exclude 1234567890,1234567891 # next batch, minus what you have
169
296
  superx engage:posts <feed-id> --include-replied true # keep posts already replied to
297
+
298
+ # Feed writes (write scope; main or linked account via --account)
299
+ superx engage:feeds:create --name "AI builders" --keyword "shipping with LLMs" --keyword "eval harness"
300
+ superx engage:feeds:create --name "Founders" --x-list https://x.com/i/lists/1234567890
301
+ superx engage:feeds:create --name "Prospects" --list-id <contact-list-id>
302
+ superx engage:feeds:update <feed-id> --name "AI builders v2"
303
+ superx engage:feeds:delete <feed-id>
170
304
  ```
171
305
 
172
- - Engage feeds are the keyword and list feeds the user set up in the app's Engage tab. `engage:feeds` gives each feed's `id`, `name`, `type` (`keywords`, `list`, `x_list`), `active`, and `fetch_units`. Feeds are created and edited in the app; the API only reads them.
306
+ - Engage feeds are the keyword and list feeds the user set up in the app's Engage tab. `engage:feeds` gives each feed's `id`, `name`, `type` (`keywords`, `list`, `x_list`), `active`, and `fetch_units`.
307
+ - Feeds can be created, renamed, repointed and deleted here. Give `engage:feeds:create` a `--name` (1-40 chars) and exactly ONE source: repeatable `--keyword` (1-5), `--x-list` (a public X list id or `x.com/i/lists/...` link), or `--list-id` (one of the user's contact lists from `lists:list`).
308
+ - A feed you create does NOT become the feed the app has open: the person keeps their place. Tell them where to find the new feed rather than assuming they will see it.
309
+ - Up to 8 feeds per account (409 `feed_limit_reached` beyond that). `engage:feeds:update` changes one source at a time and keeps the feed's id, so a feed may switch type. Deleting the feed the app has open hands the slot to the first remaining feed.
310
+ - An X list source is looked up live: those calls also draw on the tighter enrichment allowance, and a private list is a 404 `x_list_not_found`. Keyword and contact-list feeds cost no enrichment.
173
311
  - `engage:posts` returns candidate posts (text, author handle/bio/follower counts, engagement metrics, post time) plus `has_more` and the `feed`. Score and shortlist them for the user.
174
312
  - READ-ONLY BY DESIGN: there is no reply command. Replies are written and sent by a person in SuperX. Sending replies that read as inauthentic can get an X account suspended and a SuperX account terminated; AI output must be reviewed and meaningfully edited by a person before it is posted. Surface candidates and draft suggestions for the user; never claim a reply was sent.
175
313
  - `--limit` (1-50, default 20) applies to KEYWORD feeds. List feeds return one page per fetch (about 10 posts for a member list, 20 to 25 for an imported X list) and `--limit` only trims it. Page a list feed with `--exclude` (at most 100 ids per call; window the list to the most recent ids), not a bigger `--limit`.
@@ -191,20 +329,124 @@ superx signals:create-agent \
191
329
  --icp "Indie founders building SaaS in public, sharing MRR and launches" \
192
330
  --keyword "building in public" --keyword "just shipped my MVP"
193
331
 
332
+ # Watch an account and its followers as well as keywords
333
+ superx signals:create-agent --name "Naval orbit" --icp "..." \
334
+ --signal "profile:@naval" --signal "follower:@naval"
335
+
194
336
  # Lifecycle (agent id from signals:agents)
337
+ superx signals:update-agent 3 --icp "Series A founders hiring their first RevOps lead"
338
+ superx signals:update-agent 3 --list-id <contact-list-id>
195
339
  superx signals:pause-agent 3
196
340
  superx signals:resume-agent 3
197
341
  superx signals:delete-agent 3
342
+
343
+ # Signals on an existing agent (signal id from the agent's signals in signals:agents)
344
+ superx signals:add-signal 3 --type keyword_watch --query "just raised a seed round"
345
+ superx signals:add-signal 3 --type follower_watch --handle naval
346
+ superx signals:add-signal 3 --type list_watch --list https://x.com/i/lists/1234567890
347
+ superx signals:remove-signal 3 118
348
+
349
+ # Teach the scorer (lead id from signals:leads, NOT an X user id)
350
+ superx signals:feedback 4821 --fit
351
+ superx signals:feedback 4821 --not-fit
352
+ superx signals:feedback 4821 --clear
198
353
  ```
199
354
 
200
- - Signal agents are automated lead finders: they watch profiles, followers, keywords, or lists and score people against an ideal customer profile. The API creates keyword-watch agents and pauses, resumes, or deletes any agent; name/ICP/precision/destination edits happen in the app.
201
- - `signals:create-agent` requires `--name` (max 80) and `--icp` (max 500). Repeat `--keyword` for 1-5 plain-language watches ("what does the target customer post about"); omit it and 1-3 are auto-suggested from the ICP. Omit `--list-id` and a contact list named `Leads: <agent name>` is created for the leads (`destination_list_created: true` in the response). `--precision high|discovery` defaults to high. Supports `--idempotency-key`.
355
+ - Signal agents are automated lead finders: they watch profiles, followers, keywords, or lists and score people against an ideal customer profile. All four watch types, agent edits, signal add/remove and lead feedback work from here.
356
+ - `signals:create-agent` requires `--name` (max 80) and `--icp` (max 500). Repeat `--keyword` for plain-language searches ("what does the target customer post about"), and repeat `--signal "type:target"` for the other kinds (`profile:@handle`, `follower:@handle`, `list:<id or x.com/i/lists link>`, `keyword:<search>`). Keywords and signals combined are 1-5 entries; omit both and 1-3 keywords are auto-suggested from the ICP. Omit `--list-id` and a contact list named `Leads: <agent name>` is created for the leads (`destination_list_created: true` in the response). `--precision high|discovery` defaults to high. Supports `--idempotency-key`.
357
+ - A create is PARTIAL SUCCESS: entries the add path rejects come back in `warnings` (each with its `type`, `target` and a `code` such as `user_not_found`, `x_list_not_found`, `duplicate_signal`, `cap_reached`) and the agent is still created with the entries that landed. Check `warnings` and re-add the fixed ones with `signals:add-signal`; never report a mistyped handle as watched.
358
+ - `signals:update-agent <id>` changes `--name`, `--icp`, `--precision`, `--list-id` or `--status`. Editing the ICP changes how NEW leads are scored; leads already found keep their scores. An unusable `--list-id` is a 404 `list_not_found`.
359
+ - `signals:add-signal` takes one target per call. Each plan caps how many signals one agent may hold (403 `cap_reached`), an agent may watch each target once (409 `duplicate_signal`), and handle/list adds are resolved live so they also draw on the enrichment allowance. `signals:remove-signal` keeps the leads that signal already found; removing the last signal is allowed and leaves the agent finding nothing.
360
+ - `signals:feedback` records the user's verdict and teaches the scorer, so ASK before deciding for them: a wrong verdict skews which leads the agent brings next. The verdict is also mirrored onto the person's row in the agent's destination list, and shows up as `feedback`/`feedback_at` on `signals:leads`.
202
361
  - Creation returns immediately, but leads arrive ASYNCHRONOUSLY: the agent finds people over the following minutes and days. Never promise instant results; check `signals:leads` later.
203
362
  - Deleting an agent keeps its saved leads and its contact list.
204
363
  - Each lead carries the person's profile, `icp_score` and `icp_rationale` (why they matched), `deposited`/`deposited_at` (whether it has been saved to the agent's contact list yet), `discovered_at`, and `provenance` (how it was found: the action, the watched handle, the triggering post text).
205
364
  - `signals:leads` flags: `--agent <id>` (from `signals:agents`; unknown id returns 404 `agent_not_found`), `--deposited true|false`, `--since/--until` (UTC ISO-8601, on discovery time), `--limit` (max 100, default 50), `--page`.
206
365
  - An agent's `destination_list_id` joins to `lists:list` for the target list's name; deposited leads appear there as members.
207
366
 
367
+ ### Lead search and outreach (live search, briefs, drafts)
368
+
369
+ ```bash
370
+ # Find people on X right now (saves NOTHING: no agent, no stored leads)
371
+ superx signals:search \
372
+ --keywords "losing customers to churn, cancellations killing my MRR" \
373
+ --icp "B2B SaaS founders worried about retention" \
374
+ --precision discovery --max 10
375
+
376
+ # Turn people into outreach briefs saved as a dataset (exactly one source)
377
+ superx datasets:research --handles levelsio,naval --focus "audience-growth tooling" --wait
378
+ superx datasets:research --list <contact-list-id> --max 20 --wait
379
+ superx datasets:research --agent 3 --max 10 --wait
380
+ superx datasets:research --dataset <dataset-id> --max 25 --wait
381
+
382
+ # Draft one message per person onto that dataset (TEXT ONLY - nothing is sent)
383
+ superx datasets:outreach-drafts <dataset-id> \
384
+ --format "hey [first]! been following what you're building. <personalization>. would love to trade notes"
385
+ superx datasets:rows <dataset-id> --limit 50 # read every drafted message
386
+ ```
387
+
388
+ - **Nothing in this chain sends a DM.** `datasets:outreach-drafts` writes message TEXT onto the dataset's `message` column and stops there. A person reviews and sends them from the SuperX app. Never tell the user their messages have gone out, and never imply the CLI can send them.
389
+ - `signals:suggest-keywords --icp "..."` and `signals:expand-icp (--text | --url)` stage what a new agent needs before you create one: keyword ideas, and the rubric the scorer reads the ICP as. Both are FREE and create nothing. Pass a suggestion to `signals:create-agent --keyword`; the rubric has nowhere to be saved (agents are created with `--icp`), so use it to sharpen that text. `--url` reads a website and also returns an `icp_description` to pass straight to `--icp`; it costs one of the account's 20 page reads a day, shared with the app, and takes up to a minute.
390
+ - `signals:search` needs a key with the **write** scope (every non-GET API route does), even though it CREATES NOTHING. The leads exist only in that response, so save what you need. For an audience that keeps filling up on its own, use `signals:create-agent` instead. It takes up to a minute, and each lead comes from ONE matched post: `posts_count` is lifetime volume, not proof of current activity.
391
+ - `datasets:research` needs exactly one of `--handles` (max 25), `--list`, `--agent` or `--dataset`, and `--max` is 1-25 (default 10). Every hook in a brief QUOTES one of the person's real posts; proposed quotes that failed the verbatim check are dropped server-side, so a brief with no hooks is honest, not broken. More than 5 profiles run in the background (`202 collecting`) - pass `--wait` or poll `datasets:get`.
392
+ - `datasets:outreach-drafts` needs a `--format` from the USER: their template or an example message. Never invent one. `[name]`, `[first]` and `[handle]` are kept intact for per-recipient fill-in at send time. A brief with no usable hook gets an honest generic message counted in `generic`, and a draft that names a DIFFERENT recipient is discarded and counted in `contaminated` (run it again to retry those rows). Re-running overwrites every draft.
393
+ - Costs: `signals:search` is measured, at least 1 credit for a search that reaches X; `datasets:research` is a flat **1 credit per profile actually researched** (the rest are returned); `datasets:outreach-drafts` is measured and usually 1-3 credits. Research settles when the run finishes, so after a `--wait` read `superx status` for the pool rather than the response.
394
+ - The two that read X live also carry per-plan day caps (`429 ai_action_limited`) and draw on a platform-wide fair-use ceiling shared by every account. On a 429 read `error.scope`: `"account"` means the user's own daily cap, `"platform"` means the shared ceiling and their own allowance is untouched - wait for `reset_at` and retry rather than telling them they are out.
395
+
396
+ ### Writing helpers (drafts, remix, edits, checks)
397
+
398
+ ```bash
399
+ # One reply draft, in the user's voice (nothing is posted)
400
+ superx engage:reply-draft --post 1234567890 --thoughts "agree, and we saw the same thing" --tone concise
401
+ superx engage:reply-draft --text "hot take about pricing" --handle levelsio --author "Pieter Levels"
402
+
403
+ # Rewrite a post, near or far from the original
404
+ superx posts:remix --text "$(cat post.txt)" --closeness 70
405
+ superx posts:remix --text "..." --closeness 20 --instructions "make it a question"
406
+
407
+ # Change one selected piece, keeping the surrounding style
408
+ superx tools:inline-edit --text "the hook line" --full "$(cat post.txt)" --type hook
409
+ superx tools:inline-edit --text "..." --instruction "make this one line, lowercase"
410
+
411
+ # One preset rewrite of a whole post
412
+ superx tools:rephrase --type concise --text "$(cat post.txt)"
413
+
414
+ # Check a claim, and compare two drafts
415
+ superx tools:factcheck --text "X has 600M daily active users"
416
+ superx tools:predict --a "$(cat v1.txt)" --b "$(cat v2.txt)"
417
+ ```
418
+
419
+ - **Every one of these returns TEXT and posts NOTHING.** `engage:reply-draft` writes a reply for a person to review and post; there is still no reply-sending command anywhere in the CLI. Show the draft, let the user edit it, and never say a reply went out.
420
+ - `engage:reply-draft` takes exactly one of `--post <id>` (the API reads the post live, so the draft sees the real text, author and any quoted post) or `--text` with optional `--author` and `--handle`. Add `--thoughts` with what the USER wants to say - ask them, never invent an opinion for them - and `--tone engaging|humorous|creative|sarcastic|inspirational|concise`. `--post` also spends one live X lookup on top of the credit.
421
+ - `posts:remix` needs `--closeness` 0-100: 0 keeps only the idea, 100 stays very close to the original wording. Use it on a proven post the user wants to say again in their own words, then save the result with `posts:draft` or `scheduled:create`.
422
+ - `tools:inline-edit` needs `--instruction`, `--type`, or both, and works best with `--full` so the edit blends into the post around it. `--type` presets: grammar, translate, hook, details, concise, engaging, humorous, creative, sarcastic, inspirational.
423
+ - `tools:rephrase` presets: improve, grammar, translate, hook, details, clarity, engaging, humorous, positive, creative, sarcastic, inspirational, concise. The style ones write in the user's voice; grammar, translate, clarity, details and concise stay mechanical.
424
+ - `tools:factcheck` reports `result` (true, false or unknown), a one-sentence `comment` and the `sources` it read. It is a model's reading of a couple of search results, NOT a guarantee: show the sources and never present the verdict as settled. `tools:predict` scores are an opinion for comparing two drafts against each other, not a prediction of reach.
425
+ - Costs are measured AI credits: typically 1 each, and 2 for a remix or a reply draft. None of them spends a live X request except `engage:reply-draft --post`.
426
+
427
+ ### Workers (posts written for you on a schedule)
428
+
429
+ ```bash
430
+ superx workers:list # your Workers, schedules, next run times
431
+ superx workers:suggestions --limit 10 # newest posts waiting for review
432
+ superx workers:suggestions --worker 3 --status all # everything one Worker has written
433
+ superx workers:suggestions --status scheduled # the ones already queued
434
+
435
+ # Act on one (suggestion id from workers:suggestions; write scope)
436
+ superx workers:draft 4821 # save it to Drafts
437
+ superx workers:schedule 4821 --at "2026-09-15T14:00:00Z"
438
+ superx workers:dismiss 4821 # clear it out of To review
439
+ ```
440
+
441
+ - A Worker is an agent inside SuperX that writes posts for one account on a schedule. Workers are CREATED, EDITED AND RUN IN THE APP: there is no create or run command here, and no API endpoint for either. This chain reads what they wrote and acts on it.
442
+ - `workers:suggestions` defaults to `--status to_review`, the ones waiting on a person. The other values are `drafted`, `scheduled`, `dismissed` and `all`. `--worker <id>` narrows to one Worker, `--limit` (max 100, default 20) and `--page` walk the list, newest first.
443
+ - Each suggestion carries `id`, `worker_id`, `text`, `status`, `generated_at`, the `drafted_at`/`scheduled_at`/`dismissed_at` stamps, `post_id` once it has been saved, and `reference` (the kind of source the Worker wrote from). The Worker's own collection ids stay private.
444
+ - AI OUTPUT NEEDS A HUMAN: show the user the text and let them edit it before it is saved or queued. `workers:draft` saves it as written, `workers:schedule` queues it as written, and neither asks for confirmation. To change the wording first, rewrite it with `posts:remix` or `tools:rephrase` and save your version with `scheduled:create` instead, then `workers:dismiss` the original so the list stays clean.
445
+ - `workers:schedule` requires `--at` in UTC ISO-8601. The post does NOT inherit the account's Default Post Settings: it carries only what the call passes, which from the CLI is nothing beyond the time, so no auto retweet, auto plug, auto delete or auto DM. Add those afterwards with `scheduled:update`, which is also how you retime it; `scheduled:delete` cancels it.
446
+ - One suggestion can only be saved once. A second `workers:draft` or `workers:schedule` on the same id is a 400, as is acting on a dismissed one. An id belonging to another account's Worker is a 404.
447
+ - `workers:draft` and `workers:schedule` land the post in the same Drafts and Queue the rest of the CLI reads: `scheduled:list --status draft` shows a drafted suggestion, newest first, and the response gives you its `post_id` directly.
448
+ - Endpoints behind these commands: `GET /v1/workers`, `GET /v1/workers/suggestions`, `POST /v1/workers/suggestions/{id}/draft`, `POST /v1/workers/suggestions/{id}/schedule`, `POST /v1/workers/suggestions/{id}/dismiss`. The three POSTs need a key with the **write** scope. Every command here takes `--account` for an account you own (main or linked); an account someone shared with you is read-only, so a write against it returns 403 `writes_main_account_only`.
449
+
208
450
  ### Scheduling
209
451
 
210
452
  ```bash
@@ -247,6 +489,48 @@ superx scheduled:delete <post-id>
247
489
  - `scheduled:list` filters: `--status draft,scheduled,sent,error` (comma list), `--tags id,id` (any-of), `--from/--to` bounds on the scheduled time.
248
490
  - `media:upload` accepts JPG/PNG/WEBP (5MB) and GIF (15MB); a post part carries up to 4 images OR exactly 1 GIF. Uploads are capped at 100/day and expire after 24h if never attached.
249
491
 
492
+ ### Publishing now (irreversible)
493
+
494
+ ```bash
495
+ # Publishes to X the moment this returns. --idempotency-key is REQUIRED.
496
+ superx posts:publish --text "Post text" --idempotency-key "launch-2026-09-07"
497
+
498
+ # Thread, same shape as scheduled:create
499
+ superx posts:publish --part "1/ The hook" --part "2/ The close" --idempotency-key "thread-42"
500
+
501
+ # With an image and an auto retweet
502
+ KEY=$(superx media:upload ./chart.png | jq -r '.object_key')
503
+ superx posts:publish --text "Chart of the week" --media "$KEY" --alt-text "Weekly revenue line chart" \
504
+ --auto-retweet 6 --idempotency-key "chart-2026-09-07"
505
+ ```
506
+
507
+ - **Get explicit human confirmation of the exact text before running this.** It cannot be undone: the post is live on X. Use `scheduled:create --at` for anything that can wait, and `posts:draft` when the user still wants to review wording.
508
+ - `--idempotency-key` is required and is yours to choose. Reuse the SAME key on a retry: it returns the original result instead of posting again. Only use a new key for genuinely new content.
509
+ - On a timeout, retry with the SAME key. A retry inside the publish window returns 409 `idempotency_in_flight` with a `Retry-After` delay; after that the API checks whether the first attempt landed and replays its result rather than posting twice.
510
+ - No `--at`, `--title` or `--scratchpad`: a published post has no draft to organize (passing them returns 400).
511
+ - The result carries `status: "sent"`, `posted_at`, `x_post_id` and `url`.
512
+ - Advanced settings and Auto DM inherit the account's Default Post Settings exactly like `scheduled:create`; the `--no-*` forms turn one off for this post.
513
+
514
+ ### Bulk queue operations
515
+
516
+ ```bash
517
+ # Move queued posts to new times (up to 500, one transaction: all or none)
518
+ superx scheduled:bulk-retime --moves-json '[{"id":"abc","scheduled_for":"2026-09-08T15:00:00Z"}]'
519
+
520
+ # Turn Auto Retweet on for posts that do not have it (up to 100)
521
+ superx scheduled:bulk-auto-retweet --ids abc,def --auto-retweet 6 --auto-retweet-remove 4
522
+
523
+ # Delete queued posts and refund their post quota (up to 100)
524
+ superx scheduled:bulk-delete --ids abc,def
525
+ ```
526
+
527
+ - All three touch **queued posts only**. Drafts, sent posts and error rows are counted in `skipped` and are never retimed or deleted, so `updated` / `deleted` can be lower than the number of ids you sent. Delete a draft with `scheduled:delete <id>`.
528
+ - `bulk-auto-retweet` never overwrites a post's existing auto retweet; those posts land in `skipped`.
529
+ - GOTCHA: posts you create through the CLI inherit the account's Default Post Settings, so if Auto Retweet is on there they ALREADY have one and `bulk-auto-retweet` reports every id as `skipped`. Create them with `--no-auto-retweet`, or clear it per post with `scheduled:update <id> --no-auto-retweet`, before bulk-applying a different one.
530
+ - Each `scheduled_for` follows the normal window: at least 60 seconds ahead, within 18 months.
531
+ - The responses are COUNTS, not per-post results. Re-read with `scheduled:list` to see the new state.
532
+ - No idempotency key: re-running the same call converges (a retime to the same time is a no-op, an already-deleted id is skipped).
533
+
250
534
  ### Editing drafts and scheduled posts
251
535
 
252
536
  ```bash
@@ -262,7 +546,7 @@ superx scheduled:update <post-id> --clear-tags --clear-title --clear-scratchpad
262
546
  - A new `--at` alone never schedules a draft. Promotion is always explicit via `--status scheduled` (which needs a future time, provided or already set).
263
547
  - CAUTION: replacement text is a FULL replace, media included. `--text` without `--media` REMOVES any images the post carried; re-list the current `object_key`s (visible in `scheduled:list`) to keep them. Title, scratchpad, tag, and time edits never touch media.
264
548
 
265
- ### Advanced settings (auto retweet, auto delete, auto plug, super followers)
549
+ ### Advanced settings (auto retweet, auto delete, auto plug, auto DM, super followers)
266
550
 
267
551
  ```bash
268
552
  # Explicit values on create
@@ -282,17 +566,41 @@ superx scheduled:create --text "Post" --at "2026-08-01T15:00:00Z" \
282
566
  superx scheduled:create --text "Post" --at "2026-08-01T15:00:00Z" \
283
567
  --no-auto-retweet --no-auto-plug
284
568
 
569
+ # Auto DM the people who engage with the post once it is live
570
+ superx scheduled:create --text "Post" --at "2026-08-01T15:00:00Z" \
571
+ --auto-dm-message "Hey [first], here is the template I mentioned" \
572
+ --auto-dm-triggers reply,repost --auto-dm-max 50
573
+
285
574
  # Edit or remove on an existing post (no inheritance on update)
286
575
  superx scheduled:update <post-id> --auto-retweet 2
287
576
  superx scheduled:update <post-id> --no-auto-delete
577
+ superx scheduled:update <post-id> --no-auto-dm # also gives back the month's slot
288
578
  ```
289
579
 
290
580
  - On `scheduled:create`, flags you OMIT inherit the user's Default Post Settings from the SuperX app; that is the expected behavior, not a bug. Exactly five settings inherit (auto retweet, auto delete, auto plug, auto DM, Super Followers only); other composer defaults like Bluesky cross-posting never apply to API posts. Use the `--no-*` forms to turn a default off for one post.
291
581
  - On `scheduled:update` there is no inheritance: passed flags override, omitted flags keep the post's current settings, `--no-*` removes them.
292
582
  - Hours are 1-12. `--auto-plug` needs `--auto-plug-threshold` (likes); template ids come from `plug-templates:list`, unknown ids fail with `unknown_plug_template`. `--super-followers` / `--no-super-followers` toggle Super Followers only.
293
- - Auto DM has no flag: it always follows the user's app defaults. If a plan limit strips it at create time, the response carries `"auto_dm_skipped": true`; relay that to the user instead of ignoring it.
583
+ - Auto DM: `--auto-dm-message` (1-1000, `[name]` / `[first]` / `[handle]` are filled per recipient) arms it, with optional `--auto-dm-triggers reply,repost` (default reply only), `--auto-dm-max` 1-100 and `--auto-dm-batch`. `--no-auto-dm` turns it off for the post. Omitted, it follows the user's app defaults. The plan caps how many posts a month may carry one (`dm:limits` -> `posts_with_auto_dm`): when that cap strips it the post is still created and the response carries `"auto_dm_skipped": true`, so relay that instead of ignoring it. Reading a post back never shows the DM text, only that one is attached.
294
584
  - `scheduled:list` shows the applied settings per post (`auto_retweet`, `auto_delete`, `auto_plug`, `auto_dm`, `super_followers_only`), so you can verify what a post will actually do.
295
585
 
586
+ ### DM campaigns (queue only; the app sends)
587
+
588
+ ```bash
589
+ superx dm:limits # allowances before you queue anything
590
+ superx dm:campaign --recipients people.json --message "Hey [first], loved your thread"
591
+ superx dm:campaign --recipients=- --message "..." --spread # recipients from stdin
592
+ superx dm:campaign-status <campaign-id> # counts per status + the messages
593
+ superx dm:queue --status pending # everything still waiting to go out
594
+ superx dm:cancel <campaign-id> # remove the unsent ones
595
+ ```
596
+
597
+ - **Nothing is sent by these commands.** `dm:campaign` puts messages into the account's own DM queue and the SuperX app's scheduler sends them within the account's daily and monthly limits. The reply is COUNTS (`queued`, `queued_now`, `scheduled`, `skipped`, `duplicates`), never deliveries, so never tell the user their messages went out: point them at `dm:campaign-status`.
598
+ - The user is responsible for these messages under X's automation rules. Confirm the recipient list and the exact text with them before queueing, and do not queue a campaign they did not ask for.
599
+ - `--recipients` takes a JSON file (or `--recipients=-` for stdin; the `=` is required) of `[{ "x_user_id", "handle"?, "name"?, "message"?, "source_post_id"? }]`, up to 100 people. Ids come from `signals:leads`, `datasets:rows` or `lists:members`. A recipient's own `message` overrides the shared one. `[name]`, `[first]` and `[handle]` are filled per person.
600
+ - People this account messaged in the last 24 hours are skipped and counted in `duplicates`, and the account never messages itself. `--spread` places whatever today's daily allowance cannot hold over the coming days instead of skipping it.
601
+ - `dm:cancel` deletes the campaign's UNSENT rows, queued-for-now and scheduled-for-later alike, and gives the monthly commitment back. Sent messages cannot be recalled and one already going out cannot be stopped.
602
+ - Costs no AI credits. Refusals come back as `dm_limit_reached` with `scope` `month` or `day`, `dm_not_in_plan` when the plan has no DM allowance, and `reauth_required` when the X account needs reconnecting in the app.
603
+
296
604
  ### Tags
297
605
 
298
606
  ```bash
@@ -326,12 +634,20 @@ superx context:products
326
634
  superx context:products:set --url "https://superx.so" --name "SuperX" --description "X growth platform"
327
635
  superx context:products:set --id 3 --updates "Shipped the public API"
328
636
  superx context:products:delete <product-id>
637
+ superx context:products:replace --json '[{"url":"https://superx.so","name":"SuperX"}]' # FULL REPLACE
638
+
639
+ # Free helpers (no AI credits)
640
+ superx context:regenerate-style-guide # rebuild the generated guide; once an hour
641
+ superx context:scrape-product <product-id> # re-read that product's page and refresh it
329
642
  ```
330
643
 
331
644
  - What each setting affects: `--profile-description` grounds the AI's voice and personalizes the daily content mix and search; `--rules` are mandatory instructions on EVERY AI surface; `--reply-rules` and `--reply-author-name` steer generated replies; `--favorite-creators` (X usernames, max 3) inspire the writing style; `--interests` are the highest-priority topics for content suggestions; `--style-audience`/`--style-vocabulary` outrank the app's generated style guide until cleared.
332
645
  - `context:get` also returns the read-only generated style guide (`style_guide.generated`) so you can see what a cleared override falls back to.
646
+ - `context:regenerate-style-guide` rewrites that generated guide from the account's recent posts. Free, once an hour per account (429 `ai_action_limited`, `scope: "account"`, `reset_at` an hour after the last run), and it takes up to a minute. It does NOT touch `--style-audience` / `--style-vocabulary`, which keep outranking it, so a user who set overrides sees no change in output until they clear them. An account with fewer than 5 recent posts stored has them read live: that leg allows 3 attempts a day and also draws on the shared platform ceiling (both 429 `ai_action_limited`, `scope` `account` and `platform` respectively), and still too few posts returns 400 `not_enough_posts`. Shared accounts refuse it.
647
+ - `context:scrape-product <id>` re-reads a product's page and refreshes its stored name, description and details. The url comes from the SAVED product, so fix a moved url with `context:products:set --id` first. Free, on the account's 20 page reads a day shared with the app; a page that cannot be read returns 422 `scrape_failed`.
333
648
  - Caps: profile description 500, rules 500, reply rules 500, style audience 600, style vocabulary 1000 characters; 30 interests of 50 characters each; 3 favorite creators; 5 products.
334
649
  - `context:products:set --url` creates the product when it does not exist. Removing a product is reversible: re-adding the same url restores its scraped details.
650
+ - `context:products:replace` REPLACES the whole product list: any product whose url is missing from the array is removed. Read `context:products` first and send every product the user should keep, or use `context:products:set` to change one in place. `'[]'` removes every product.
335
651
  - Writes need a key with the write scope. Unlike scheduling, context writes work on ANY linked or shared account via `--account` (they are per-account settings). On a share with Editor permission they return 403 `editor_restricted`: only the account owner can change these. These settings shape ALL future AI output for the account; confirm with the user before changing rules or the profile description.
336
652
 
337
653
  ### Queue settings (posting schedule)
@@ -377,14 +693,18 @@ superx articles:unschedule <article-id> # back to draft, quota refunds
377
693
  superx articles:publish <article-id> # LIVE NOW, irreversible, needs X Premium
378
694
  superx articles:delete <article-id>
379
695
 
380
- # AI cover (60-100s, spends AI credits against daily/monthly caps)
696
+ # AI cover (60-100s, a flat 25 AI credits, plus the daily/monthly cover caps)
697
+ superx articles:cover-styles # styles saved in the app, with their ids
381
698
  superx articles:cover <article-id>
699
+ superx articles:cover <article-id> --style-id <style-id> # render in a saved style
382
700
  superx articles:cover <article-id> --style "dark, minimal, geometric" --no-attach
383
701
  ```
384
702
 
385
703
  - Publishing and scheduling spend post quota; the article needs a title and some content first.
386
704
  - X enforces its own article limits (10 drafts/day, 5 publishes/day) and requires X Premium; those surface as publish failures.
387
705
  - `articles:cover` generates from the article's TITLE. Attach is the default; `--no-attach` keeps the current cover and you can attach later with `articles:update --cover-url`.
706
+ - Steer the look with `--style-id` (one of the styles the user saved in the app, listed by `articles:cover-styles`) or `--style` (a one-off description), never both: passing both is a 400. An unknown style id is a 404 `cover_style_not_found`. Styles are saved and deleted in the app.
707
+ - A cover generation costs a FLAT 25 AI credits on the API, whatever the render actually costs, and the response reports `meta.credits_charged`. A generation that fails outright is refunded in full; one that TIMES OUT keeps the charge because the cover may still have landed, so run `articles:get` and look at the cover before retrying.
388
708
  - A publish timeout is AMBIGUOUS: run `articles:get` and check `status` before retrying.
389
709
 
390
710
  ### Docs
@@ -443,7 +763,7 @@ for attempt in 1 2 3; do
443
763
  done
444
764
  ```
445
765
 
446
- Rate limits per key: 60 reads/min and 10,000 reads/day; 10 writes/min and 300 writes/day. Every authenticated response carries `X-RateLimit-*` headers; `superx status` shows the current window. On 429 the stderr message includes the retry delay.
766
+ Rate limits are per account owner and scale with the plan: reads, writes, enrichment and feed fetches each have their own per-minute and per-day windows, and media uploads are capped at 100 per key per day. Every authenticated response carries `X-RateLimit-*` headers; `superx status` shows the current window and the AI credit pool. On 429 the stderr message includes the retry delay. Current numbers: https://docs.superx.so/rate-limits
447
767
 
448
768
  ### Pattern 5: Batch a week of content
449
769
 
@@ -459,12 +779,60 @@ superx scheduled:list --status scheduled
459
779
 
460
780
  ---
461
781
 
782
+ ## Playbooks
783
+
784
+ Full recipes with flags and MCP tool chains: [PLAYBOOKS.md](./PLAYBOOKS.md). Pick by goal, then open that entry.
785
+
786
+ ### Recaps and analytics
787
+ - **Weekly Growth Recap**: the week in review, one focus for next week. `posts:analytics` -> `posts:list` -> `signals:leads` -> `replies:received`
788
+ - **Growth Plan Builder**: multi-week plan tied to real numbers. `posts:analytics` -> `posts:list` -> `replies:list` -> `queue:get`
789
+ - **Post Post-Mortem**: why one post over- or underperformed. `posts:list` -> `posts:analytics` -> `x:user-posts`
790
+ - **Top Performers Breakdown**: the shape the best posts share. `posts:list` -> `posts:analytics`
791
+ - **My Replies Report**: which replies earned attention. `replies:list`
792
+
793
+ ### Content
794
+ - **Daily Post Ideas**: two or three drafts for today. `scheduled:list` -> `posts:list` -> `posts:draft` -> `scheduled:create`
795
+ - **Week of Posts**: a week of drafts on the real slots. `posts:list` -> `queue:get` -> `posts:draft` -> `scheduled:create`
796
+ - **Thread Builder**: notes turned into a thread draft. `posts:draft` -> `scheduled:create`
797
+ - **Repurpose a Winner**: the best post, reworked. `posts:list` -> `posts:remix` -> `scheduled:create`
798
+ - **Viral Format Remix**: proven shapes in this account's voice. `inspiration:search` -> `posts:draft` -> `scheduled:create`
799
+ - **Trending Now Scan**: what is working in the niche now. `inspiration:search`
800
+
801
+ ### Queue
802
+ - **Cadence & Queue Audit**: gaps, pile-ups, a cadence verdict. `queue:get` -> `scheduled:list` -> `posts:list` -> `scheduled:update`
803
+ - **Queue Reshuffle**: move and rewrite queued posts. `scheduled:list` -> `scheduled:bulk-retime` -> `scheduled:update`
804
+
805
+ ### Replies (stop at a draft, by design)
806
+ - **Reply Sprint**: five audience replies, each with a draft. `replies:received` -> `engage:reply-draft`
807
+ - **Reply to Any Post**: context plus one strong reply draft. `x:post` -> `x:replies` -> `engage:reply-draft`
808
+
809
+ ### Leads
810
+ - **Who Is This Person?**: a fast read plus your history. `x:user` -> `x:user-posts` -> `contacts:get` -> `contacts:replies`
811
+ - **Your Warmest Leads**: the people engaging most, ranked. `contacts:list` -> `contacts:replies`
812
+ - **Instant Lead Hunt**: live search for matching people now. `signals:suggest-keywords` -> `signals:search`
813
+ - **Standing Lead Agent**: an agent that keeps finding leads. `signals:expand-icp` -> `signals:create-agent` -> `signals:leads`
814
+ - **Lead Review**: found leads, prioritized and checked. `signals:agents` -> `signals:leads` -> `x:user-posts` -> `signals:feedback`
815
+
816
+ ### Audiences, research and DMs
817
+ - **Profile Research Briefs**: structured briefs plus a CSV. `datasets:research` -> `datasets:rows` -> `datasets:export`
818
+ - **DM-Ready Audience Builder**: a clean DM-able audience. `datasets:collect` -> `datasets:get` -> `datasets:add-to-list`
819
+ - **Sentiment Slice**: keep only the people who said it. `datasets:list` -> `datasets:refine` -> `datasets:rows`
820
+ - **Audience Export**: everyone who engaged a post, as CSV. `datasets:collect` -> `datasets:export`
821
+ - **My Content Export**: your own posts or replies, as CSV. `datasets:collect` -> `datasets:export`
822
+ - **Warm Outreach Pipeline**: briefs, a message each, queued. `datasets:research` -> `datasets:outreach-drafts` -> `dm:campaign`
823
+ - **Reply-to-DM Campaign**: DM the people who replied. `datasets:collect` -> `datasets:refine` -> `dm:campaign`
824
+
825
+ ### Settings
826
+ - **Teach SuperX Your Rules**: standing rules for AI drafts. `context:get` -> `context:set`
827
+
828
+ ---
829
+
462
830
  ## Common Gotchas
463
831
 
464
832
  1. **Naive timestamps are rejected (400)**. Always include `Z` or an offset: `2026-08-01T15:00:00Z`, not `2026-08-01T15:00:00`.
465
833
  2. **Schedule window**: `--at` must be at least 60 seconds in the future and within 18 months.
466
834
  3. **Read-only keys cannot write**: `scheduled:create`/`scheduled:delete` with a read-only key returns 403 `insufficient_scope`. Check `superx me` for the key's scopes.
467
- 4. **Writes are main-account-only**: passing a linked or shared account to `scheduled:create` returns 403 `writes_main_account_only`. Reads accept any account `superx accounts` lists. The exceptions are `context:*` and `queue:set`, which are per-account settings.
835
+ 4. **Shared accounts are read-only for writes**: writes work on your main account or any linked account (pass the same `--account` you used to read it). Accounts shared with you by other people return 403 `writes_main_account_only` for post, article, signal and contact-list member writes, and for `posts:draft`. `context:*` and `queue:set` are per-account settings that do accept a shared account.
468
836
  5. **Images need an upload first**: `--media` takes `object_key`s from `media:upload`, never file paths or URLs. Unknown keys return 400 `invalid_media`; a presign whose bytes were never PUT returns 400 `media_not_uploaded`. Video is not supported.
469
837
  6. **Size caps**: max 25 thread parts, 25,000 characters total.
470
838
  7. **Rate limited (429)**: `rate_limited` on stderr with a retry delay. Back off; do not hammer.
@@ -489,7 +857,33 @@ superx scheduled:list --status scheduled
489
857
  26. **`context:set` list flags REPLACE the stored list**: `--interests` and `--favorite-creators` overwrite what is there; include every value the user should keep. `""` on a string flag clears it (style-guide overrides then revert to the generated guide). These settings steer all future AI output; confirm with the user before changing them.
490
858
  27. **`queue:set --slots-json` REPLACES the whole schedule** and re-flows queued posts onto the new slots. Read the current slots with `queue:get` first and send the full set. `'[]'` clears every slot and leaves the queue all-custom. `reflow.bailed: true` means the settings saved but no post moved.
491
859
  28. **`editor_restricted` (403)**: the account is shared with the key owner with Editor permission. Editors can change queue settings but not context settings. Only the account owner can.
492
- 29. **`engage:posts --limit` is keyword-feeds only**: list feeds return one page of about 10 to 25 posts per fetch, so page them with `--exclude` (the ids you already have, at most 100 per call), not a bigger `--limit`. Each plan also has a daily feed-fetch allowance (separate from reads) and a list feed that rotates its members counts as 3 fetches, so fetch big pages a few times a day rather than polling. Posts a fetch returns count as seen and are demoted in later fetches, in the app as well as here.
860
+ 29. **`lists:add-members` takes ids SuperX already knows**: it does no live lookup, so any id in the response's `not_found` was never added. Add those with `lists:add-member --handle <handle>` one at a time (that path resolves live and costs an enrichment unit).
861
+ 30. **`contacts:get` and `contacts:notes:add` are known-contacts only**: they resolve engagers, contact-list members and scored signal leads, and 404 `contact_not_found` on any other id, including ids SuperX has a profile for. Get ids from `contacts:list`, `lists:members` or `signals:leads`; there is no general profile lookup yet. `contacts:notes`, `contacts:notes:update` and `contacts:notes:delete` are NOT restricted: they work on any id you already have a note on, so notes stay reachable after someone drops out of your contacts.
862
+ 31. **Notes written through the API are attributed to the acting account**, not to a separate API identity: `created_by` on a note is the account named by `--account` (your main account when omitted). A note id from a different contact returns 404 `note_not_found`.
863
+ 32. **`context:products:replace` REPLACES the whole product list**: products whose url is missing from `--json` are removed. Read `context:products` first, or use `context:products:set` for a single-product edit.
864
+ 33. **`posts:publish` is irreversible and needs `--idempotency-key`**: it posts to X immediately. Confirm the exact text with the user first. Without the key the command exits 1; on a timeout retry with the SAME key (409 `idempotency_in_flight` means the first attempt is still running, so wait for the `Retry-After` delay and retry that same key again). `--at`, `--title` and `--scratchpad` are rejected.
865
+ 34. **The bulk commands only touch QUEUED posts**: `scheduled:bulk-retime`, `scheduled:bulk-auto-retweet` and `scheduled:bulk-delete` skip drafts, sent posts and error rows, and `bulk-auto-retweet` also skips posts that already have an auto retweet. They answer with counts, so compare against `scheduled:list` rather than assuming every id was applied.
866
+ 35. **`replies:list` page 1 can carry `metrics_pending` items**: replies sent from the SuperX app in the last 4 hours are merged in with zero metrics until X reports them, so page 1 can hold slightly more items than `--limit`. Later pages and `--since`/`--until` queries never include them.
867
+ 36. **`engage:posts --limit` is keyword-feeds only**: list feeds return one page of about 10 to 25 posts per fetch, so page them with `--exclude` (the ids you already have, at most 100 per call), not a bigger `--limit`. Each plan also has a daily feed-fetch allowance (separate from reads) and a list feed that rotates its members counts as 3 fetches, so fetch big pages a few times a day rather than polling. Posts a fetch returns count as seen and are demoted in later fetches, in the app as well as here.
868
+ 37. **A feed you create is not the feed the app has open**: `engage:feeds:create` saves the feed but never switches the person's view. Tell them where to find it. The cap is 8 feeds (409 `feed_limit_reached`), `engage:feeds:update` takes one source at a time, and deleting the open feed hands the slot to the first remaining one.
869
+ 38. **An X list feed or signal costs enrichment and needs a PUBLIC list**: `engage:feeds:create --x-list`, `engage:feeds:update --x-list` and `signals:add-signal --type list_watch` each spend one enrichment unit and 404 `x_list_not_found` on a private or deleted list. Keyword and contact-list sources cost none.
870
+ 39. **`signals:create-agent` is partial success**: entries that fail come back in `warnings` with a `code`, and the agent is still created from the ones that landed. Read `warnings` before telling the user what the agent watches; re-add fixed entries with `signals:add-signal`.
871
+ 40. **`signals:feedback` takes the numeric LEAD id from `signals:leads`, not an X user id**, and it trains the scorer. Ask the user for the verdict rather than inferring one. An id from another account returns 404 `lead_not_found`; a repeated `signals:remove-signal` returns 404 `signal_not_found`.
872
+ 41. **`articles:cover --style-id` and `--style` are mutually exclusive** (400 if both are sent). Style ids come from `articles:cover-styles`; an unknown one returns 404 `cover_style_not_found`.
873
+ 42. **A dataset has to be `ready` before you read its rows, export it or add it to a list.** Poll `datasets:get <id>` until `status` is `ready`; anything else returns 409 `dataset_not_ready`, and a `failed` dataset has to be rebuilt in the SuperX app. Datasets expire after 30 days, after which the id 404s.
874
+ 43. **`datasets:add-to-list` dedupes by person and skips rows without an X account id** (research rows sometimes have none), so `added + duplicates` can be lower than the dataset's `row_count`. `skipped_without_id` counts only the rows with no usable X account id or handle; repeat rows for the same person (a replier who replied twice) are deduped silently and are not counted anywhere. Re-running the same command is safe: people already in the list come back in `duplicates`.
875
+ 44. **The `x:*` lookups share a 300/day allowance with Ask SuperX in the app**, on top of the enrichment allowance (1 unit each, 3 for `x:replies`, 2 for `x:post --quotes` or a handle SuperX has never seen). Look up what the user actually asked about; do not sweep an account's network. `429 lookup_quota_exceeded` covers three cases and the body says which: your own allowance is used up (it carries `limit`), the SuperX-wide allowance is used up (no `limit`, not your budget), or the counter could not be verified and the call was refused rather than run unmetered (no `limit`, short `retry_after`). Honour `retry_after` rather than assuming midnight, and report it rather than retrying in a loop. Repeats within 15 minutes come from a server-side cache and do not touch the daily allowance.
876
+ 45. **`x:replies` is a sample, not every reply**: the best-liked direct replies from up to 3 relevance-ranked pages, not chronological, and it cannot page further. It also does NOT exclude the account owner's own replies, unlike the same view in the app. Use the audience collections (`datasets:list`) when someone needs everyone who replied. And a `post_not_found` on `x:post` can be a transient upstream failure rather than a deleted post, so retry once before saying it is gone.
877
+
878
+ 46. **`audience:list` pages by cursor, not by page number.** Pass `pagination.next_cursor` back as `--cursor`; there is no `--page` and no `total`. Quote `meta.synced_count` for the size of the list, but note it may exceed the rows a full walk returns (edges that were later removed are still counted). Check `meta.status`: anything but `complete` means SuperX is still syncing, and `meta.is_capped: true` on the follow lists means it is the most recent slice, not everyone. `meta.account_id` is the account id you pass to `--account`; the X user id is `meta.x_account_id`. Repliers and reposters only cover a rolling 90 days.
879
+ 47. **`engage:mentions` costs 3 feed fetches per call and shows more than the app.** It draws on the same daily feed allowance as `engage:posts`, so read one page and work from it rather than polling. It does NOT apply the skipped/blocked filtering the app's Mentions tab does (that lives with the app), and by default it leaves out mentions already replied to on X unless you pass `--include-replied true`.
880
+ 48. **`datasets:collect` can return before the collection is done.** `status: "collecting"` means zero rows so far and work still running: use `--wait`, or poll `datasets:get` until `ready`, and never state a row count from the create result. A collection whose size cannot be established up front also runs in the background. It costs one of 10 collections a day shared with Ask SuperX in the app, only one runs per account at a time (409 `collection_in_progress`), and an empty result creates no dataset at all (`data: null` plus a `note`) and gives the daily slot back.
881
+ 49. **Nothing in the outreach chain sends a DM.** `datasets:outreach-drafts` writes message TEXT onto a research dataset and stops there; a person reviews and sends them from the SuperX app. Never say messages were sent and never offer to send them. If the user explicitly asks, you may QUEUE them with `dm:campaign` (one recipient entry per person, each with its own `message`), which is still an enqueue: the app sends. Ask the user for the `--format`; never invent one. Re-running overwrites every draft, `generic` counts messages written with no personal claims (that brief had no usable hook), and `contaminated` counts drafts discarded for naming a different recipient - run it again to retry those rows.
882
+ 50. **`signals:search` saves nothing and `datasets:research` charges per profile.** A search creates no agent and no stored leads, so keep what the user needs from that response; use `signals:create-agent` when they want leads to keep arriving. Research is a flat 1 credit per profile ACTUALLY researched (handles that cannot be resolved, and people with no recent posts, come back in `skipped` and are refunded), and over 5 profiles it runs in the background: never state a brief count from a `collecting` result. `datasets:refine` also creates a dataset, so it spends one of the same 10 collections a day.
883
+ 51. **`ai_action_limited` has two scopes.** Read `error.scope` before telling the user anything: `"account"` is their plan's own daily cap for that action, `"platform"` is a fair-use ceiling on live-data actions shared by every SuperX account. On `"platform"` their own allowance is untouched, so wait for `reset_at` and retry rather than reporting them as out of quota.
884
+ 52. **The writing helpers draft, they never publish.** `engage:reply-draft`, `posts:remix`, `tools:inline-edit`, `tools:rephrase`, `tools:factcheck` and `tools:predict` all return TEXT and stop there - nothing is posted, scheduled or sent. Unlike `posts:draft`, they also accept an account shared with you. Show the output, let the user edit it, and use `posts:draft`, `scheduled:create` or `posts:publish` when they say so. A `tools:factcheck` verdict is a model reading two search results: report it with its sources, never as settled fact.
885
+ 53. **The free helpers cost nothing but are not unlimited.** `context:regenerate-style-guide` is once an hour per account and does not override a manual style-guide setting; `context:scrape-product` and `signals:expand-icp --url` share 20 page reads a day with the SuperX app, and `--url` also inherits the app's limit of 10 prefills per 10 minutes (that one comes back as `rate_limited` and clears in about a minute, so retry rather than reporting a daily budget); `signals:suggest-keywords` and `signals:expand-icp --text` have no ceiling of their own, so do not loop them - each one is a model call. All five send `X-Credits-Remaining` but no `X-Credits-Charged`, because nothing was charged. All four commands still need a key with the write scope: they are POSTs, and every non-GET API route needs it.
886
+ 54. **A DM campaign is an ENQUEUE, not a send.** `dm:campaign` returns counts of what was QUEUED; the SuperX app's scheduler sends them later, within the account's daily and monthly DM limits, so never report messages as delivered from that response - `dm:campaign-status` and `dm:queue` show what actually went out. Confirm the recipient list and the exact text with the user first: they are responsible for these messages under X's automation rules. Cancel the unsent ones with `dm:cancel`; anything already sent cannot be recalled.
493
887
 
494
888
  ---
495
889
 
@@ -513,22 +907,64 @@ superx posts:list --since "2026-06-01T00:00:00Z" --until "2026-07-01T00:00:00Z"
513
907
  superx posts:analytics --since "2026-06-01T00:00:00Z"
514
908
  superx replies:list --limit 20
515
909
  superx inspiration:search "build in public" --sort outlier --limit 10
910
+ superx inspiration:media "founder morning routine" --limit 10 # cross-platform media index (--limit up to 120, no paging)
516
911
  superx contacts:list --sort engagement --limit 20
517
912
  superx contacts:replies <id> --sort most_liked
913
+ superx contacts:get <x-user-id>
914
+ superx contacts:notes <x-user-id>
518
915
  superx replies:received --sort most_liked --limit 20
519
916
  superx lists:list
520
917
  superx lists:members <list-id> --q "founder"
918
+ superx audience:list followers --limit 100 # system lists: cursor paging, no --page
919
+ superx engage:mentions --sort top # live @-mentions (costs 3 feed fetches)
920
+ superx signals:search --keywords "..." --icp "..." # live lead search, saves nothing
521
921
  superx signals:agents
522
922
  superx signals:leads --agent 3 --deposited false
523
923
  superx engage:feeds
524
924
  superx engage:posts <feed-id> --limit 50
925
+ superx datasets:list
926
+ superx datasets:get <dataset-id>
927
+ superx datasets:rows <dataset-id> --limit 50
928
+ superx datasets:export <dataset-id> # CSV file here; --out - streams to stdout
929
+ superx datasets:collect --source repliers --target <post-url> --wait # build one, poll until ready
930
+ superx datasets:refine <dataset-id> --criterion "..." --wait # filter by what each person wrote
931
+ superx datasets:research --handles a,b,c --wait # briefs, 1 credit per profile
932
+ superx datasets:outreach-drafts <dataset-id> --format "..." # message TEXT only, nothing sent
933
+
934
+ # Live X lookups (enrichment units + a shared 300/day allowance)
935
+ superx x:post <id-or-url> # one public post, live (--quotes for quotes)
936
+ superx x:replies <id-or-url> --limit 20 # best-liked direct replies (a sample)
937
+ superx x:user <handle> # one public profile, live
938
+ superx x:user-posts <handle> --no-reposts # one live page of their latest posts
939
+
940
+ # Contact writes (main or linked account)
941
+ superx contacts:notes:add <x-user-id> --body "..." # Private note, never posted
942
+ superx contacts:notes:update <x-user-id> <note-id> --body "..."
943
+ superx contacts:notes:delete <x-user-id> <note-id>
525
944
 
526
945
  # Contact list writes (main or linked account)
527
946
  superx lists:add-member <list-id> --handle levelsio
528
947
  superx lists:remove-member <list-id> <member-id>
948
+ superx lists:create --name "Founder prospects"
949
+ superx lists:rename <list-id> --name "Q4 prospects"
950
+ superx lists:delete <list-id> # List + membership; the people stay
951
+ superx lists:add-members <list-id> --x-user-ids 44196397,944883311 # <=500, ids SuperX knows
952
+ superx lists:remove-members <list-id> --member-ids m1abc,m2def # <=500
953
+ superx datasets:add-to-list <dataset-id> --list-id <list-id> # people from a ready dataset
954
+
955
+ # Engage feed writes (main or linked account)
956
+ superx engage:feeds:create --name "AI builders" --keyword "shipping with LLMs"
957
+ superx engage:feeds:create --name "Founders" --x-list https://x.com/i/lists/1234567890
958
+ superx engage:feeds:update <feed-id> --name "AI builders v2"
959
+ superx engage:feeds:delete <feed-id>
529
960
 
530
961
  # Signal agent writes (main or linked account)
531
962
  superx signals:create-agent --name "..." --icp "..." --keyword "..." # Lead finder
963
+ superx signals:create-agent --name "..." --icp "..." --signal "profile:@naval"
964
+ superx signals:update-agent <id> --icp "..." --list-id <contact-list-id>
965
+ superx signals:add-signal <id> --type follower_watch --handle naval
966
+ superx signals:remove-signal <id> <signal-id>
967
+ superx signals:feedback <lead-id> --fit # or --not-fit / --clear
532
968
  superx signals:pause-agent <id>
533
969
  superx signals:resume-agent <id>
534
970
  superx signals:delete-agent <id>
@@ -547,6 +983,36 @@ superx scheduled:list --status draft,scheduled
547
983
  superx scheduled:list --tags <tag-id>
548
984
  superx scheduled:delete <id>
549
985
 
986
+ # Publish NOW (irreversible; key required, reuse it on a retry)
987
+ superx posts:publish --text "Post" --idempotency-key k1
988
+
989
+ # Writing helpers (text in, text out; nothing is posted)
990
+ superx engage:reply-draft --post <id> --thoughts "..." --tone concise
991
+ superx posts:remix --text "..." --closeness 70
992
+ superx tools:inline-edit --text "..." --full "..." --type hook
993
+ superx tools:rephrase --type concise --text "..."
994
+ superx tools:factcheck --text "..."
995
+ superx tools:predict --a "..." --b "..."
996
+
997
+ # DM campaigns (queued only; the SuperX app sends them)
998
+ superx dm:limits
999
+ superx dm:campaign --recipients people.json --message "Hey [first], ..."
1000
+ superx dm:campaign-status <campaign-id>
1001
+ superx dm:queue --status pending
1002
+ superx dm:cancel <campaign-id>
1003
+
1004
+ # Free helpers (no AI credits)
1005
+ superx context:regenerate-style-guide
1006
+ superx context:scrape-product <product-id>
1007
+ superx signals:suggest-keywords --icp "B2B SaaS founders worried about churn"
1008
+ superx signals:expand-icp --text "Indie founders building SaaS in public"
1009
+ superx signals:expand-icp --url superx.so
1010
+
1011
+ # Bulk queue operations (queued posts only; answers are counts)
1012
+ superx scheduled:bulk-retime --moves-json '[{"id":"abc","scheduled_for":"2026-09-08T15:00:00Z"}]'
1013
+ superx scheduled:bulk-auto-retweet --ids abc,def --auto-retweet 6
1014
+ superx scheduled:bulk-delete --ids abc,def
1015
+
550
1016
  # Tags
551
1017
  superx tags:list
552
1018
  superx tags:create "Launch week" --color amber
@@ -561,7 +1027,9 @@ superx articles:update <id> --file v2.md
561
1027
  superx articles:schedule <id> --at "2026-08-01T15:00:00Z"
562
1028
  superx articles:unschedule <id>
563
1029
  superx articles:publish <id>
1030
+ superx articles:cover-styles
564
1031
  superx articles:cover <id> --style "minimal"
1032
+ superx articles:cover <id> --style-id <style-id>
565
1033
  superx articles:delete <id>
566
1034
 
567
1035
  # Context settings (AI writing background)
@@ -571,6 +1039,7 @@ superx context:set --interests "indie hacking,SaaS" # replaces the list
571
1039
  superx context:products
572
1040
  superx context:products:set --url "https://superx.so" --name "SuperX"
573
1041
  superx context:products:delete <id>
1042
+ superx context:products:replace --json '[{"url":"https://superx.so"}]' # FULL REPLACE
574
1043
 
575
1044
  # Queue settings (posting schedule; 0 = Sunday)
576
1045
  superx queue:get
@@ -583,4 +1052,4 @@ superx --help # All commands
583
1052
  superx scheduled:create --help # Command help
584
1053
  ```
585
1054
 
586
- Strategy lives in [PLAYBOOK.md](./PLAYBOOK.md). Read it before creating content (Rule 2).
1055
+ Strategy lives in [PLAYBOOK.md](./PLAYBOOK.md). Read it before creating content (Rule 2). Goal-shaped recipes live in [PLAYBOOKS.md](./PLAYBOOKS.md): open the entry that matches what the user asked for.