superx CLI is a thin client for the SuperX API: every command maps to a /v1 endpoint and prints clean JSON. It doubles as the tool the superx-agent skill teaches AI agents to use.
Install
superx-cli; the installed binary is superx.
Log in
Create an API key in the SuperX app at app.superx.so/account?tab=api, then:~/.superx/credentials.json (file mode 0600). Use superx login --key "sxk_..." for a non-interactive login, superx status to verify, and superx logout to remove the stored key.
Authentication for CI and agents
Set an environment variable instead of logging in:SUPERX_API_URL to a full base URL including the path (default: https://api.superx.so/v1).
Commands
Flags mirror the API’s query parameters:
--account, --limit, --page, --since/--until, --sort, --type, --status, --from/--to. Run any command with --help for its full flag list and examples.
Datasets are created in the SuperX app (Ask) for now; the CLI reads them. datasets:rows, datasets:export and datasets:add-to-list need a dataset whose status is ready, so poll datasets:get <id> first; anything else returns 409 dataset_not_ready. Export is CSV only (XLSX downloads stay in the app), and datasets:export writes a filename matching the app download’s naming pattern (superx-dataset-<title>-<date>.csv) unless --out says otherwise.
The x:* commands read X live rather than SuperX’s stored data. They cost the tighter enrichment allowance (1 unit each, 3 for x:replies, 2 for x:post --quotes or an x:user-posts handle SuperX has never seen) and share an allowance of 300 live lookups a day with Ask SuperX in the app; over it is a lookup_quota_exceeded error that resets at midnight UTC. Repeat lookups within 15 minutes may come from a server-side cache. x:replies samples the best-liked replies from up to 3 pages, so it is not the full reply list. inspiration:media costs no enrichment and is not personalised: with no query it browses the newest media. It returns no media file URLs; source_url opens the original post on its own platform. It has no pagination, returning at most 120 items per query, so ask for --limit 120 and filter locally rather than calling it repeatedly. --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 counts against the daily search cap.
Note that drafts have no scheduled time, so --from/--to filters on scheduled:list exclude drafts; use --status draft to list them. scheduled:list returns the most recently updated first, so page 1 is the newest work; walk back with --page rather than raising --limit. A --from/--to request is a calendar query instead and comes back in scheduled-time order, oldest first.
Workers are the scheduled AI writers set up in the SuperX app, and each run drops a batch of posts into the app’s To review queue. workers:list reads the Workers and workers:suggestions reads what they wrote. Creating, editing and RUNNING a Worker stays in the app, so the CLI has no command for any of those. workers:draft saves one suggestion to Drafts, workers:schedule --at queues it, and workers:dismiss clears it out of To review without touching any post. The text is saved exactly as the Worker wrote it, so show it to the person first: to change the wording, rewrite it with posts:remix or tools:rephrase, save your version with scheduled:create, and dismiss the original. A suggestion can only be saved once (a second call is a 400 already_saved, a dismissed one already_dismissed), and the response carries the new post_id, which from then on is an ordinary post for scheduled:list, scheduled:update and scheduled:delete.
To post an image: superx media:upload ./chart.png prints an object_key, then superx scheduled:create --text "..." --media "<object_key>" --alt-text "..." attaches it (comma-list up to 4 image keys, or exactly 1 GIF). For threads with media, pass the full parts array as JSON via --parts-json. Images are capped at 5MB (GIF 15MB) and 100 uploads per day.
posts:publish sends the post to X the moment it returns, so confirm the exact text with a person first and use scheduled:create --at for anything that can wait. --idempotency-key is required there: reuse the same key on a retry and the original result comes back instead of a second post, and a retry that lands while the first attempt is still publishing returns 409 idempotency_in_flight with a delay to wait. The result carries status: "sent", posted_at, x_post_id and url.
The three bulk commands only touch posts in the QUEUE: drafts, sent posts and error rows are counted as skipped and are never retimed or deleted, and scheduled:bulk-auto-retweet also skips posts that already have their own auto retweet. Posts created through the CLI or API inherit the account’s Default Post Settings, so if Auto Retweet is on there every one of them already carries an auto retweet and comes back as skipped: create them with --no-auto-retweet (or clear it with scheduled:update --no-auto-retweet) if you want to bulk-apply a different one. They answer with counts rather than per-post results, so re-read with scheduled:list to see the new state. None of them takes an idempotency key: re-running the same call converges.
Advanced settings on scheduled:create: flags you omit inherit your Default Post Settings from the SuperX app. Exactly five settings inherit this way (auto retweet, auto delete, auto plug, auto DM, Super Followers only); other composer defaults such as Bluesky cross-posting or share-with-followers are never applied to API posts. --auto-retweet <hours> (1-12, plus --auto-retweet-remove <hours>), --auto-delete <hours> (1-12, plus --auto-delete-threshold <views>, default 1000), --auto-plug <templateId> with --auto-plug-threshold <likes> (template ids from plug-templates:list), --auto-dm-message <text> (always required to arm an auto DM; 1-1000, with optional --auto-dm-triggers reply,repost where retweet is accepted as an alias of repost, --auto-dm-max <n> and --auto-dm-batch), and --super-followers set explicit values; the --no-* forms (--no-auto-retweet, --no-auto-delete, --no-auto-plug, --no-auto-dm, --no-super-followers) turn a setting off for that post. On scheduled:update there is no inheritance: flags you pass override, omitted flags keep the post’s current settings, and --no-* removes them. An auto DM goes to the people who reply to or repost the post once it is live; your plan caps how many posts a month may carry one (dm:limits shows posts_with_auto_dm), and if that cap strips it at create time the post is still created and the response carries auto_dm_skipped: true.
Writing helpers: engage:reply-draft, posts:remix, tools:inline-edit, tools:rephrase, tools:factcheck and tools:predict all return TEXT and post NOTHING. engage:reply-draft writes one reply for a person to review and post; there is no reply-sending command anywhere in the CLI, so never report a reply as sent. Give it exactly one of --post <id> (the post is read live, which costs one live lookup on top of the credit) or --text, and use --thoughts for what the person actually wants to say rather than inventing an opinion for them. posts:remix needs --closeness 0-100: 0 keeps only the idea, 100 stays very close to the wording. A tools:factcheck verdict is a model’s reading of a couple of search results, so report it with its sources and never as settled fact, and tools:predict scores compare two drafts against each other rather than predicting reach. Each of these costs measured AI credits: typically 1, and 2 for a remix or a reply draft.
DM campaigns queue, they do not send. dm:campaign takes --recipients as a JSON file (or --recipients=- for stdin; the = is required) of [{ "x_user_id", "handle"?, "name"?, "message"?, "source_post_id"? }], up to 100 people, plus a shared --message in which [name], [first] and [handle] are filled per recipient. The messages go into the account’s own DM queue and the SuperX app’s scheduler sends them within the account’s daily and monthly limits, so the reply is counts (queued, queued_now, scheduled, skipped, duplicates), not deliveries: read dm:campaign-status to see what actually went out. When every recipient is skipped nothing is queued and the id comes back null, so there is no campaign to look up. People messaged in the last 24 hours are skipped and counted in duplicates, the account never messages itself, and --spread places whatever today’s allowance cannot hold over the coming days. dm:cancel deletes the unsent rows and gives the monthly allowance back; a campaign that exists but has nothing left answers cancelled: 0. Costs no AI credits; dm:limits shows the plan’s numbers. You are responsible for these messages under X’s rules on automation and unsolicited contact.
Free helpers: context:regenerate-style-guide, context:scrape-product, signals:suggest-keywords and signals:expand-icp cost no AI credits. context:regenerate-style-guide rewrites the guide every writing command above reads, once an hour per account; your manual overrides (context:set --style-audience / --style-vocabulary) still outrank it. context:scrape-product and signals:expand-icp --url read a page, and each account can read 20 pages a day, shared with the SuperX app; --url also inherits the app’s short-term limit of 10 prefills per 10 minutes, which comes back as rate_limited and clears in about a minute. context:regenerate-style-guide on an account with fewer than 5 stored posts reads them live, and that leg is capped at 3 attempts a day. signals:expand-icp returns a rubric with nowhere to save it (agents are created with --icp), so use it to sharpen that description; a keyword suggestion, on the other hand, goes straight into signals:create-agent --keyword or signals:add-signal. All four need a key with the write scope: they are POSTs, and every non-GET route on the API needs it.
Lead search and outreach: signals:search runs ONE live keyword search and returns the leads inline. It creates no signal agent and stores no leads, so keep what you need from the response and use signals:create-agent when the person wants leads to keep arriving. datasets:research turns handles, a contact list, an agent’s leads or a dataset into outreach briefs saved as a dataset; more than 5 profiles run in the background, so pass --wait. datasets:outreach-drafts then writes one message per person onto that dataset. The drafts are text and nothing is sent: they live on the dataset (read them with datasets:rows) and a person sends them from the SuperX app. Ask the person for the --format; never invent one. datasets:refine filters a dataset by what each person wrote into a NEW dataset, leaving the source untouched, keeps rows it cannot judge (counted as unclear), and counts against the same 10 dataset collections a day. On a 429 ai_action_limited, read error.scope: account is the plan’s own daily cap, platform is a fair-use ceiling shared by every account, so wait for reset_at rather than reporting the account as out.
Engage feeds and signals: engage:feeds:create saves a feed but deliberately does not switch the feed the person has open in the app, so tell them where to find it. Up to 8 feeds per account, engage:feeds:update changes one source at a time (a feed may change type and keeps its id), and deleting the open feed hands the slot to the first remaining one. An --x-list source and the profile_watch, follower_watch and list_watch signal types are looked up live: those calls spend one unit of the tighter enrichment allowance and only PUBLIC X lists work. signals:create-agent is a partial success, so read the warnings array before reporting what an agent watches and re-add the fixed entries with signals:add-signal. signals:feedback trains the scorer, so ask the person for the verdict rather than deciding for them.
Article bodies are markdown in both directions: headings, lists, blockquotes, bold/italic/strikethrough, links, images by URL, and bare X post URLs as embeds. Constructs the X Articles format cannot express (code blocks, horizontal rules) degrade to plain text and are reported in a warnings array.
Context settings (context:get / context:set) are the background SuperX’s AI uses when writing for the account: the profile description grounds the voice, --interests drive content suggestions, --rules are mandatory instructions on every AI surface, --reply-rules and --reply-author-name steer generated replies, --favorite-creators (max 3) inspire the style, and --style-audience/--style-vocabulary outrank the app’s generated style guide until cleared with "". Boolean flags support --no-* negation. Caps: 500 characters for the profile description, rules, and reply rules; 600 for the style audience; 1000 for the style vocabulary; 30 interests; 3 creators; 5 products.
Contacts and lists: contacts:get takes a numeric X user id (from contacts:list, lists:members, or signals:leads) and returns the stored profile plus the lists that person is in. It resolves only your KNOWN contacts, meaning people who have replied to or reposted your posts, members of your contact lists, and scored signal leads; any other id returns 404 contact_not_found, even one SuperX holds a profile for. contacts:notes:add follows the same rule: you can only start a note on a known contact. The other contacts:notes* commands work on any id you already have a note on. --refresh refreshes a stale profile from X and counts against the tighter enrichment limit, so leave it off unless the follower counts have to be current. Notes are private to SuperX and never posted, and a note written through the CLI is attributed to the account it was written as. lists:add-members adds up to 500 people in one call by X user id and does no live lookup, which is why it costs one write and no enrichment; ids SuperX has never seen come back in not_found and are not added, so add those with lists:add-member --handle. lists:delete also stops any signal agent depositing into that list until the agent is repointed in the SuperX app. context:products:replace is a full replace by url: read context:products first and send every product the account should keep, or use context:products:set to change one in place.
JSON output
stdout is clean JSON for every command exceptsuperx docs (markdown), so output pipes straight into jq:
0 on success, 1 on error.
Agent skill
The superx-agent repo packages the CLI as a skill for Claude Code and compatible agent tools:PLAYBOOK.md, a distilled SuperX growth strategy the agent follows when deciding what and when to post.
It also ships with PLAYBOOKS.md, the 29 goal-shaped recipes documented on Agent playbooks: each one gives the command chain for a named SuperX skill, the matching MCP tools, and the point where the agent hands back to a person.