If you run social for a handful of clients, the slowest part of the month is not the writing. It is the clicking. You open a dashboard, pick a client workspace, upload the same cover image again, set the timezone, hit schedule, and repeat that eleven times. The Creator OS CLI lets you schedule client posts from a terminal instead, so a whole month of recurring content becomes one command you run once.
This post is a concrete agency workflow: install the CLI, point it at one client at a time, keep their calendar in a file, queue the posts, and read results back without leaving the shell. It is not a tour of every platform. For that, go to the docs.
client folder
---------------
acme/
calendar.json -- posts + platforms + media URLs
README.md -- timezone, tone, hashtags
$ creatoros auth:check
$ creatoros posts:bulk-upload --file acme/calendar.json --dryRun
$ creatoros posts:bulk-upload --file acme/calendar.json
$ creatoros analytics:posts --from 2026-01-01 --sortBy engagement
one workspace -> one API key -> one clientWhy an Agency Would Schedule Client Posts From the CLI
An agency dashboard does three jobs well: writing captions, looking at a calendar, approving drafts. It does a fourth job badly: repeating a known pattern for a known client on a known date.
Recurring content is exactly that fourth job. A dentist posts three times a week. A podcast client posts an episode every Tuesday and a clip every Thursday. A coffee roaster posts a product shot every Monday and a Reel every Friday. Once you know the pattern, the interesting work is over, and the rest is data entry.
The CLI turns that pattern into a file. You write the posts once, keep the file in the client folder, and re-run it next month after swapping dates and media. Nothing about the schedule lives in your memory.
You also get a clean boundary between clients. A Creator OS API key is pinned to one workspace, which is one set of socials. An agent or script holding Acme’s key cannot post to your other client’s accounts. That matters when a freelance contractor runs the script for one account and not the others.
What the Creator OS CLI Actually Does
The CLI is @creatoros/cli, a package that talks to the same Creator OS backend as the web app, the iOS app, the REST API and the hosted MCP server. Anything you can schedule in the dashboard, the CLI can schedule too, plus a few things a dashboard does not do well.
The parts an agency will use most:
creatoros posts:createqueues a post to specific accounts or platforms, with media, cover, hashtags, timezone and an optional draft flag.creatoros posts:bulk-upload --file calendar.jsonpushes a whole calendar from a file, with a--dryRunflag to validate first.creatoros media:upload <file>uploads a file once and returns amed_id you can reuse on every platform.creatoros analytics:posts,analytics:dailyandanalytics:best-timeread performance back.creatoros inbox:commentsandinbox:replyhandle the reply queue.creatoros accounts:healthandaccounts:listtell you whether a client’s connections still work before you blame the script.
There is also creatoros validate:post-length --text "...", which checks a caption against the limits of the platforms you are posting to. Run it before a bulk upload and you catch the over-long one at 9am instead of when it fails at 6pm.
The full flag list lives at https://www.creatoros.ca/docs/cli. If you would rather have an agent do the scheduling than a shell script, the open-source Social Agents harness is the same idea with a conversation in front of it, and it is covered at social media management for agencies.
Install and Authenticate @creatoros/cli for a Client Workspace
Install Node, then install the CLI globally or run it with npx:
npm install -g @creatoros/cli
creatoros auth:check
creatoros profiles:list
creatoros accounts:list
auth:check confirms the key on the machine is live. profiles:list shows the workspaces that key can reach, and accounts:list shows the connected accounts inside the active workspace. For an agency, that second command is the important one: it tells you which client you are pointed at before you schedule anything.
If an account is missing or the token expired, creatoros accounts:connect <platform> opens the connection flow, and creatoros accounts:health reports the state of what is already connected. Run health at the start of every month. Expired tokens are the number one cause of a failed bulk upload, and they are silent until the post fails.
Create the API key inside Creator OS and keep one key per client. Because a key is pinned to a single workspace, a leaked key cannot touch another client’s accounts. It is a small discipline that saves a large conversation.
Map a Client Content Calendar to a Config File
The bulk upload takes a JSON file. The shape mirrors what the REST API accepts, so a simple post is an object with content, platforms, media and a schedule. Here is one client’s March:
{
"posts": [
{
"content": "New episode: how we cut our render time in half.",
"platforms": ["instagram", "youtube", "linkedin"],
"media": ["https://cdn.example.com/ep-42-clip.mp4"],
"schedule_at": "2026-03-03T14:00:00Z",
"timezone": "America/Toronto",
"post_type": "reel"
},
{
"content": "Three mistakes we made before episode 40.",
"platforms": ["threads", "x"],
"schedule_at": "2026-03-05T15:30:00Z",
"timezone": "America/Toronto",
"draft": true
}
]
}
Two details matter. First, the timezone is stored with the post, so a Toronto client at 2pm stays at 2pm even if you run the script from a laptop in Lisbon. Second, one clip in the file can go to Instagram, YouTube and LinkedIn at once, and Creator OS applies each platform’s own rules underneath. Vertical video becomes a Short on YouTube. The simple form fills the TikTok consent flags for you if TikTok is in the platform list, while the advanced form lets you set per-platform options and a top-level TikTok object.
Before pushing anything, validate:
creatoros posts:bulk-upload --file acme/march.json --dryRun
creatoros posts:bulk-upload --file acme/march.json
The dry run is the cheapest QA step you will ever add to a content workflow. It catches a bad media URL, a platform you meant to remove, or a date you typed as 2025.
Write the Script: Queue Recurring Posts Per Client
A month of posts for one client is a shell loop. Suppose the coffee roaster posts the same three captions every Monday, Wednesday and Friday, and only the product image changes:
#!/bin/bash
set -euo pipefail
DATES=$(date -d "next month" +%Y-%m)
CAPTIONS=(
"This week's roast: Ethiopia Guji, notes of peach."
"Grinder setting for the Guji: 22 clicks, 1:16 ratio."
"Behind the roast: 11 minutes, first crack at 9:40."
)
IMAGES=(
"https://cdn.example.com/roast-1.jpg"
"https://cdn.example.com/grind-1.jpg"
"https://cdn.example.com/behind-1.jpg"
)
for i in 0 1 2; do
creatoros posts:create \
--text "${CAPTIONS[$i]}" \
--platforms instagram,facebook,threads \
--media "${IMAGES[$i]}" \
--scheduledAt "${DATES}-$((i*2+1))T13:00:00Z" \
--timezone "America/Vancouver"
done
Three commands, three posts, three platforms each. The captions live in the script or in a text file next to it. Next month you change the images and re-run.
If you would rather drive this from an AI app, the same workspace is reachable over the hosted MCP server at https://mcp.creatoros.ca/mcp. Add it as a custom connector in Claude, pick the client’s workspace, and you can ask for the same batch in plain language. The tools are the same operations: create_post, update_post, upload_media_from_url, get_best_time_to_post. Read-only connections only see read tools, and the API refuses writes from them, so a client-facing account can be given read access without risk.
If you want that agent path spelled out, the Social Agents harness is open source, and the video editing skills that pair with it are on the KevBuildsApps YouTube channel. There is also a dedicated post on Cursor MCP social media if your team lives in an editor rather than a browser.
Schedule Repeating Posts Without Re-Uploading Media
Uploading the same 40MB video three times is the waste the CLI removes. creatoros media:upload sends the file once and returns a med_ id. Every later post references that id instead of the URL:
MED=$(creatoros media:upload ./ep-42-clip.mp4)
creatoros posts:create --text "Episode 42 is live." \
--platforms instagram,youtube,linkedin \
--media "$MED" --scheduledAt "2026-03-03T14:00:00Z" \
--timezone "America/Toronto"
creatoros posts:create --text "Episode 42, the 60 second cut." \
--platforms instagram,tiktok,threads \
--media "$MED" --scheduledAt "2026-03-05T18:00:00Z" \
--timezone "America/Toronto"
Two platforms sets, one upload. Note the limits that come with reuse. Instagram’s API cannot attach trending audio, so sound has to be baked into the file before upload. TikTok videos publish public-only on a Business app connection unless you send them as drafts. Reusing one file across platforms is fine; expecting every platform to treat it identically is not.
For covers, --cover takes a med_ id or a URL, and --coverAt takes a timestamp in milliseconds to grab a frame. Reels take a custom cover. YouTube takes custom thumbnails on long-form, not on Shorts.
One more thing worth scripting: comment-to-DM funnels. creatoros automations:create takes a name, an account, keywords, a DM message and an optional comment reply, and automations:logs shows what fired. A client with a lead magnet can have the funnel set up once and running for months. The same pattern works for a long-form show, and social media scheduling for podcasters walks through the episode-plus-clip cadence.
Read Analytics Back in the Same Terminal Session
After the posts ship, you do not need to switch tools to see whether they worked:
creatoros analytics:posts --from 2026-03-01 --platform instagram \
--sortBy engagement --limit 20
creatoros analytics:daily --from 2026-03-01 --to 2026-03-31 \
--platform youtube
creatoros analytics:best-time --platform linkedin
analytics:posts ranks posts by engagement or date. analytics:daily gives account-level metrics per day. analytics:best-time returns the posting windows the data supports, which is a good input for next month’s calendar file. Follower stats are on accounts:follower-stats, which takes a date range and a granularity of daily, weekly or monthly.
If you report to clients, pipe the output into a file per client per month and keep them side by side. The analytics API post is worth reading if you want the same numbers in your own dashboard. Trackable go.creatoros.ca short links add click stats to the same picture, which matters when a client cares about traffic rather than likes.
When a post fails, creatoros posts:list --status failed finds it, posts:get explains it, and posts:retry retries it. No need to retype the caption.
Handle Multiple Clients, Tokens, and Failure Cases
Run one client at a time, with one key. A shell script that loops over three clients and three keys is a script that will eventually post the dentist’s Reel to the coffee roaster. Keep a folder per client, put the key in that folder’s environment file, and start every run with creatoros accounts:list so you can see whose accounts are loaded.
Then handle the three failures that actually happen:
- Missing platform. If a network in a post is not connected, Creator OS returns it in
missing_platformsand still publishes to the rest. That is the behavior you want at scale. Log it and fix the connection later, rather than losing the whole post. - Expired token.
accounts:healthcatches it before a run. Add it to the top of the script withset -eand the run stops instead of half-succeeding. - Wrong caption length.
validate:post-lengthcatches it for text posts. Run it over the caption file before the bulk upload.
Errors come back in one shape, { error: { code, message, status } }, at both the CLI and the REST API, so one error handler covers everything. If you prefer webhooks over polling, creatoros webhooks:create --url https://your-tool.com/hook --events post.published,comment.received registers an endpoint, and each delivery is signed with an X-CreatorOS-Signature header. That is how an agency feeds a client’s published posts into a Slack channel or a spreadsheet without anyone opening a dashboard.
When to Use the CLI Instead of the Dashboard
Use the dashboard when the work is new: writing, reviewing, approving, and looking at a calendar you are still designing. Use the CLI when the work is known: a repeating schedule, a batch of evergreen posts, a media file that needs to go to four platforms, a monthly analytics pull you do anyway.
Both read and write the same workspace, which is the point. You are not choosing a side. You are moving the repetitive half out of the browser and into a file you can diff, review and re-run. If you also want an agent doing the drafting and the replying, that path is covered too, and the walkthroughs live on the KevBuildsApps YouTube channel. The launch video for the open-source tools, including the video editing skills that turn a raw talking-head clip into an animated short, is at https://www.youtube.com/watch?v=-QBJH_PK3pY.
One caveat: the CLI schedules and reports. It does not decide what your client should say. That part stays yours.
Get started with Creator OS
The Creator plan is $19.99/month or $59.99/year and covers up to 8 connected accounts, 7 socials plus Skool. Agency plans cover 5 sets of socials (up to 40 connected accounts) for $49/month or $399/year, and 10 sets (up to 80 accounts) for $99/month or $599/year. API keys, the MCP server, the CLI and the agent skills are included in every plan, so the workflow above costs nothing extra.
Create an account at creatoros.ca/sign-up, then read the CLI docs for the full flag reference and the MCP docs if you want an AI app driving it. For getting a single post out to every network, see post to all social media at once, and for the Instagram specifics that trip up bulk uploads, see schedule Instagram posts with Claude. If you work mostly with threaded platforms, the Threads scheduler post covers the shape of a thread item.