@usesocial/cli
v0.12.3
Published
A CLI for LinkedIn and X: outreach, posting, and audience insights from any shell.
Downloads
3,900
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 login
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, x sync timeline, x sql |
| "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, scope selection, and billing. | |
| logout | Revoke the session and clear the saved token. | |
| connect linkedin | Print a LinkedIn connection URL and poll for approval. | write |
| connect x | Print an X OAuth URL and poll for approval. | 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 |
| billing | Show seats, subscription, and current usage billing. | |
| billing portal | Print the hosted billing portal URL. | |
| usage | Aggregate proxy calls and usage. | |
| logs | Recent proxy calls. | |
| config account | Read or set the default connected account selector. | local |
| 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; omit target for your own account. Costs usage. | |
| 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; pass --page or configure a default Page. Costs usage. | |
| 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; 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 |
| 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, timeline, 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 } }. - 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 login, 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 login runs a device-authorization flow. It asks what access to
grant, sends a magic link, waits for browser approval, stores the returned token
in your OS keyring, and confirms billing checkout when a seat is needed.
Sessions last two years unless revoked. social account logout revokes the
session and removes the stored token.
social account login requires an interactive terminal and is not supported from
CI, background jobs, or agent-mediated setup flows.
social account billing prints the current seat/subscription snapshot plus
aggregate usage billing. 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. Cache hits are free; fresh upstream reads are metered. 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}'
social x sync timeline
social x sql "SELECT text, url FROM x_timeline ORDER BY created_at DESC LIMIT 20" \
| 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"
social x sync timeline
social x sql "SELECT text, url FROM x_timeline ORDER BY created_at DESC LIMIT 50"
# 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.
