@usesocial/cli
v0.19.9
Published
A CLI for LinkedIn and X: outreach, posting, and audience insights from any shell.
Readme
LinkedIn & X CLI. One install, one login, and your agent can run distribution work across X and LinkedIn: outreach, posting, audience insights, and the follow-up loops between them from any shell.
social is built for people who live in a terminal with an agent open and are
on the hook for their own distribution. The work you keep meaning to do - see
who engaged, find the people worth reaching out to, learn from those who post
better, keep the funnel warm - becomes something you can hand to the agent you
already trust with your code.
Published as @usesocial/cli on npm; the binary is social.
Install
curl -fsSL https://usesocial.dev/install.sh | bashOr with Homebrew:
brew install usesocial/tap/cliUpdates
social checks for newer CLI and skill versions in the background only when
stderr is an interactive terminal. Notices are concise, printed to stderr, and
never change stdout JSON. CI, non-TTY shells, DO_NOT_TRACK, and
SOCIAL_DO_NOT_TRACK suppress the check.
Run a fresh local-only check any time:
social updateIt returns { "cli": ..., "skill": ... } with status and updateCommand
fields. It does not authenticate, call providers, or spend usage.
Quickstart
social account setup
social account connect linkedin
social linkedin profile
social account connect x
social x profileWhat you can hand your agent
| You ask | The agent reaches for |
| --- | --- |
| "Surface the ten warm contacts worth reaching out to this week." | linkedin search people, linkedin reactions, linkedin sql |
| "Pull everyone who reacted to my last LinkedIn post and flag the warm leads." | linkedin posts <target>, linkedin reactions, linkedin profile |
| "Read this creator's recent posts and break down what makes them land." | linkedin posts <target>, x tweets <target> |
| "Find what people are saying about AI agents this week and summarize the themes." | linkedin search posts |
| "Triage my inbox and draft replies for approval." | sync messages, sql, linkedin message, x message |
| "Show this week's company Page visitors and invite the approved prospects." | linkedin page visitors, linkedin page invite |
| "Draft a reply to this thread and post it once I approve." | linkedin comment, x post |
Commands
The CLI prints compact JSON. Use social schema, social schema --list, or
social schema "<command path>" for the machine-readable command tree.
Commands marked write mutate your account and require write scope. Commands marked local update local CLI state or the local mirror.
Targets
Targets accept usernames, profile/post/conversation/company URLs, LinkedIn URNs,
or typed IDs such as profile_id:<id>, post_id:<id>, chat_id:<id>,
conversation_id:<id>, company_id:<id>, and request_id:<id>. Bare IDs are
not accepted.
Body text
Posts, comments, messages, message edits, and connection-request notes read freeform text from stdin. There is no text positional:
echo "gm" | social x post
social linkedin post < draft.md
social linkedin requests send @username < note.txtPipe a JSON object for advanced payload fields. Raw LinkedIn proxy calls also read a JSON envelope from stdin:
social linkedin proxy < request.jsonPagination
Live list reads take --limit. X lists and LinkedIn posts/connections
continue with --cursor from .meta.cursor; LinkedIn search, comments,
reactions, and jobs continue with --offset. sql does not paginate —
use SQL LIMIT and ORDER BY.
Your data is local
sync pulls your own data down; it is explicit and costs usage. sql queries
that local mirror; it is free, instant, and read-only. Named read commands call
the live network and cost usage; x tweets <target> and
linkedin posts <target> require a target. Writes act.
sync output is always { data, meta }: bare sync lists collections under
.data[], while collection summaries and --reset results live under .data.
sync <collection> --since 2026-05-04 (ISO date or datetime) pulls only newer
items where the bare sync listing shows supportsSince: true — cheaper than a
full re-pull. sync <collection> --reset clears a collection's local rows and
sync state so the next sync rebuilds it.
sync <collection> --timeout 900 opts into a wall-clock wait budget, in seconds,
for rate-limit handling. LinkedIn sync may sleep and retry while the next wait
fits the budget; X keeps its current no-new-retry behavior.
Rate-limit JSON includes retryAfterSeconds, resumeAt, retryCommand,
hint, and syncResume. When syncResume.cursorPersisted is true, already
synced pages are saved and the listed retryCommand resumes from the saved
cursor. For parent/child message syncs, the hint says when an exact cursor
resume is not safe and the re-run may re-fetch unfinished pages.
social x sync messages
social x sql "SELECT sender_username, text, datetime(created_at/1000,'unixepoch') AS at FROM x_messages ORDER BY created_at DESC LIMIT 20" \
| jq '.items[]'The X inbox query gets sender_username from the x_messages view; no extra
profile lookup is needed.
Top level
| Command | Description |
| --- | --- |
| social account | Auth state, connected accounts, login/logout, connect/reconnect/disconnect, billing, usage, logs, and cache config. |
| social schema | Print the command tree, inspect one command, emit the compact runnable index, or emit full contracts. |
| social update | Check for CLI and skill updates; prints JSON and never calls providers. |
| social x <...> | X operations. |
| social linkedin <...> | LinkedIn operations. |
| social feedback bug\|feature | Send a bug report or feature request to the maintainers (report text from stdin). |
social account
| Command | Description | |
| --- | --- | --- |
| (bare) | Show who is signed in and list connected accounts. | |
| login | Device sign-in and scope selection. | |
| logout | Revoke the session and clear the saved token. | |
| connect linkedin [--account-id <id>] | Start a LinkedIn connection, or resume the exact returned account. | write |
| connect x [--account-id <id>] | Start an X connection, or resume the exact returned account. | write |
| reconnect linkedin <account> | Re-auth an existing LinkedIn account. | write |
| reconnect x <account> | Re-auth an existing X account. | write |
| disconnect linkedin <account> | Disconnect a LinkedIn account. | write |
| disconnect x <account> | Disconnect an X account. | write |
| default get <platform> | Read the shared default account for LinkedIn or X. | |
| default set <platform> <account> | Set the shared default account for LinkedIn or X. | write |
| billing | Show Social LinkedIn and Social X subscriptions, seats, and X usage. | |
| billing portal | Print the hosted billing portal URL. | |
| usage | Aggregate proxy calls and usage. | |
| logs | Recent proxy calls. | |
| config page | Read or set the default LinkedIn company Page selector. | local |
| config cache ttl | Read or set the live-read proxy cache TTL in seconds. | |
social linkedin
| Command | Description | |
| --- | --- | --- |
| profile [target] | Fetch a profile; omit target for your own account. | |
| posts <target> | Live posts for a person or company; target required. | |
| comments <target> | List a post's comments. | |
| reactions <target> | List a post's reactions. | |
| connections [target] | Live connection graph read under flat LinkedIn proxy usage; omit target for your own account. | |
| company <target> | Fetch a company profile. | |
| jobs <target> | List a company's job postings. | |
| search people\|posts\|jobs\|companies <keywords> | Search LinkedIn. | |
| page visitors | Read company Page visitor analytics under flat LinkedIn proxy usage; pass --page or configure a default Page. | |
| page invite <user...> | Invite one or more users to follow the company Page selected by --page or default config. | write |
| proxy | Forward a raw LinkedIn JSON envelope from stdin via Unipile. | write |
| sync [collection] | Pull your own connections, posts, messages, or requests into the local mirror under flat LinkedIn proxy usage. | local |
| sql [query] | Query your local mirror with read-only SQL - free; bare sql prints compact schema metadata. | |
| post | Create a post (body from stdin). | write |
| comment <target> | Comment on a post (body from stdin). | write |
| react <target> | React to a post; use --type for non-like reactions. | write |
| requests send <target> | Send a connection request (optional note from stdin). | write |
| requests accept request_id:<id> | Accept a received connection request. | write |
| requests cancel request_id:<id> | Cancel a sent request or refuse a received connection request. | write |
| message <target> | Send a message (body from stdin). | write |
| message <target> delete message_id:<id> | Delete one of your own messages. | write |
| message <target> edit message_id:<id> | Edit one of your own messages (new text from stdin). | write |
| messages <target> mark read | Mark a conversation read. | write |
| messages <target> mark unread | Mark a conversation unread. | write |
social x
| Command | Description | |
| --- | --- | --- |
| profile [target] | Fetch a profile; omit target for your own account. | |
| tweets <target> | Live posts for a user; target required. | |
| mentions [target] | List posts mentioning a user; omit target for your own account. | |
| liked [target] | List posts a user liked; omit target for your own account. | |
| followers [target] | Live follower graph read; omit target for your own account. Costs usage. | |
| following [target] | Live following graph read; omit target for your own account. Costs usage. | |
| tweet <target> | Fetch a single post. | |
| replies <target> | List replies to a post; accepts post_id:<id>, conversation_id:<id>, or a post URL. | |
| quotes <target> | List quote posts of a post. | |
| likers <target> | List users who liked a post. | |
| reposters <target> | List users who reposted a post. | |
| sync [collection] | Pull your own tweets, followers, following, bookmarks, liked, mentions, or messages into the local mirror; costs usage. | local |
| sql [query] | Query your local mirror with read-only SQL - free; bare sql prints compact schema metadata. | |
| post | Create a post (body from stdin). | write |
| message <recipients> | Send a DM (body from stdin). | write |
| like <target> / unlike <target> | Like or unlike a post. | write |
| follow <target> / unfollow <target> | Follow or unfollow a user. | write |
| repost <target> / unrepost <target> | Repost or undo a repost. | write |
| bookmark <target> / unbookmark <target> | Add or remove a saved post. | write |
| delete <target> | Delete one of your own posts. | write |
Built for agents
- Everything speaks JSON: success on stdout, structured errors on stderr.
- Platform reads return one envelope: lists use
.items[], single resources use.data, metadata lives under.meta. Sync commands use{ data, meta }.social accountservice commands return bare JSON;account logsreturns{ items, meta: { cursor } }. - X single-resource reads keep partial expansion failures under
.meta.errorsand returned expansion objects under.meta.includes, so the primary resource remains directly usable at.data. - Schema-backed planning:
social schema --listis the compact runnable index. - Local SQL is the free surface for your own synced data.
# SQL insight: synced contacts you have never messaged.
# Run `social linkedin sync connections` and `social linkedin sync messages` first.
social linkedin sql "SELECT c.user_name, c.user_username, c.user_profile_url FROM li_connections c LEFT JOIN li_messages m ON m.sender_id = c.user_id WHERE m.id IS NULL ORDER BY c.created_at DESC LIMIT 100" \
| jq '.items[]'
# Live fan-out: review recent posts, fan out to reactions, rank warm contacts.
social linkedin posts profile_id:<profile-id> --limit 25 > /tmp/recent-posts.json
jq -r '.items[].id' /tmp/recent-posts.json \
| xargs -I{} social linkedin reactions post_id:{} --limit 100 --offset 0 \
| jq -s '[ .[] | .items[] ]
| group_by(.sender.id)
| map({person: .[0].sender, signals: length})
| sort_by(-.signals) | .[0:15]'Exit codes
| Code | Meaning | Agent action |
| ---: | --- | --- |
| 0 | Success | Continue. |
| 2 | Usage or validation error | Fix the command, flags, IDs, JSON body, or local input - server-side failures are exit 5. |
| 3 | Not found | Check the resource ID or pick a different item. |
| 4 | Auth or scope error | Run social account setup, or log out and choose the needed scope. |
| 5 | API, proxy, or unexpected error | Retry later or surface the server error. |
| 7 | Rate limited | Back off, using retryAfterSeconds, resumeAt, and retryCommand when present. |
Auth
social account setup authenticates the Social account, then asks Autumn to
authorize a reusable payment method. In a terminal it guides browser approval;
in CI and agent shells it is a bounded pollable command with
pending_approval, pending_billing, and ready states. While the payment
method is not ready, setup returns checkoutURL. The hosted page authorizes the
card; setup never selects or purchases a provider plan.
Sessions last two years unless revoked. social account logout revokes the
session and removes the stored token. Non-interactive callers should surface the
returned approval or checkout URL, then rerun social account setup until it is
ready.
social account connect <platform> starts or resumes a server-owned partial
account that purchases only that provider's plan or next seat, or the applicable
legacy Social Pro seat during transition. It normally charges the stored card
directly before returning hosted provider approval. In a non-TTY shell, omit
--account-id on the first call, capture the returned accountId, and pass it
back as --account-id <accountId> on every poll. Surface paymentURL only when
pending_billing says customer action is required, then surface connectURL
for provider approval. Replaying a connected account ID is stable; omit
--account-id after completion only to connect another account.
social account billing prints Social LinkedIn and Social X independently.
Social LinkedIn costs $20 per connected account with flat proxy usage. Social X
costs $20 per connected account, includes 15,000 monthly credits per account
with one-month rollover, and offers $15 top-ups for another 15,000 credits.
social account billing portal opens the hosted billing portal when possible
and always prints the portal URL as JSON.
Cache config
There are two cache layers.
The proxy cache applies to live reads only. X cache hits spend no credits; LinkedIn proxy usage is flat whether or not a request hits the cache. Configure the default:
social account config cache ttl 3600Override one live read when the command lists --header:
social linkedin profile @username -H "Cache-Control: no-cache"
social linkedin profile @username -H "Cache-Control: no-store"
social linkedin profile @username -H "Cache-Control: max-age=60"The local mirror is separate: run sync when you want newer local data, then
query it with sql. SQL reads show local freshness in meta.cache.tables and auto-upgrades in meta.cache.migration when a migration runs:
social x sql "SELECT sender_username, text FROM x_messages ORDER BY created_at DESC LIMIT 5" \
| jq '{cache: .meta.cache}'Agents should watch .meta.cost when it is present during high-fanout loops, use
social account billing for the current plan snapshot, and use
social account usage or social account logs after a run to summarize spend.
Examples
# LinkedIn local mirror.
social linkedin sync messages
social linkedin sql "SELECT sender_name, text, datetime(created_at/1000,'unixepoch') AS at FROM li_messages ORDER BY created_at DESC LIMIT 20"
social linkedin sql "SELECT user_name, user_username FROM li_requests WHERE type='received' ORDER BY created_at DESC LIMIT 25"
# LinkedIn live reads.
social linkedin profile
social linkedin page visitors --page company_id:<company-id> --since 2026-05-01T00:00:00Z
PAGE1=$(social linkedin posts profile_id:<profile-id> --limit 25)
NEXT=$(echo "$PAGE1" | jq -r '.meta.cursor // empty')
[ -n "$NEXT" ] && social linkedin posts profile_id:<profile-id> --limit 25 --cursor "$NEXT"
social linkedin reactions post_id:<post-id> --limit 100 --offset 0
# X local mirror.
social x sync messages
social x sql "SELECT sender_username, text FROM x_messages ORDER BY created_at DESC LIMIT 20"
social x sql "SELECT text, url FROM x_bookmarks ORDER BY created_at DESC LIMIT 50"
social x sql "SELECT username, name, followers_count FROM x_followers ORDER BY followers_count DESC LIMIT 100"
# X live reads.
social x tweets profile_id:<x-user-id> --limit 30
social x replies post_id:<post-id> --limit 25
# Writes (body via stdin).
echo "gm" | social x post
social linkedin post < draft.md
social linkedin page invite profile_id:<profile-id> @username --page company_id:<company-id>
echo "Loved your launch notes." | social linkedin requests send profile_id:<profile-id>
# LinkedIn raw proxy.
social account config page company_id:<company-id>
social linkedin proxy < request.json
# Usage / billing.
social account billing
social account billing portal
social account usage
social account logs --limit 20 --from 2026-05-01T00:00:00Z \
| jq -r '.items[] | [.createdAt, .platform, .method, .path, .responseStatus, .cacheStatus, .usageUSD] | @tsv'
# Command schema.
social schema
social schema --list
social schema --leaves
social schema "linkedin requests send"
social schema "x post"
# Updates.
social updateLinks
- Pricing and limits: https://usesocial.dev/pricing
- Terms: https://usesocial.dev/terms · Privacy: https://usesocial.dev/privacy
Built by founders who needed their agents to keep distribution moving.
