Our AI social media agent in production: a queue filled 3 weeks ahead, copy rewritten for each network, script checks, human approval, and sending through the Zernio API.
swanbase cover for the AI social media agent tutorial with human approval, with LinkedIn, X and Instagram logos

An AI social media agent prepares your posts, rewrites each caption to fit each network, checks the limits and schedules the send. You keep a single job: read and approve. At swanbase, our AI social media agent has been running in production since October 3, 2026 on three accounts (LinkedIn, Instagram, X). It fills a queue three weeks ahead, runs every caption through check scripts, then waits for your "ok" before calling the Zernio API.

As of October 12, 2026, the queue holds 90 created posts, 81 recorded approvals and 73 scheduled posts, the last one set for April 20, 2027. This tutorial walks through the five-step pipeline, with our thresholds, our commands and three dated pitfalls.

Our queue as of October 12, 2026: 90 posts created, 81 approvals, 73 scheduled

What is an AI agent for managing social media?

An AI agent for managing social media is a program driven by a language model that chains several tools toward one goal: produce posts, adapt them, check them, then schedule them. It keeps state (the queue), reads sources (content you have already produced) and acts on a third-party service (the publishing API).

AI agent or scheduling tool

Three families of tools can automate social media publishing. With Buffer or Metricool, you schedule text you wrote yourself. An n8n or Zapier automation follows a fixed scenario. The agent adds the model's judgment: it picks the next quote, shortens a caption that runs too long for X, and restarts the writing after a failed check.

Ours combines Python scripts and calls to Claude, launched from Claude Code. The model writes. The scripts check and schedule.

How work splits between the agent and you

The agent fills the calendar, rewrites for each network, runs the checks and calls the API. You decide what gets published. One rule holds the whole thing together: only a human can move a post from "to review" to "approved". The day our agent broke that rule, we reverted everything within the hour (see step 4).

How a post moves through our queue

Every post lives in a single JSON file, the queue: format, slot, networks, caption, media and history.

The five steps of our AI social media agent, from the queue to the Zernio API

Six statuses and a single human gate

A post follows this cycle:

to_review -> (revising -> to_review)* -> approved -> scheduled -> published
             skipped (slot skipped)   rejected (declined)   error

Three statuses concern you. In to_review, you need to read the post. In approved, you have signed off on it. In scheduled, Zernio holds it with its date. We leave the rest to the scripts. The revising status kicks in when you ask for a change: a Claude agent rewrites the caption and puts the post back in to_review, with your request logged in the history.

A typical week with one format per day

We set our standard week on September 28, 2026: one format per working day, at noon. Monday a carousel, Tuesday a quote, Wednesday a tool (plus a video at 6 p.m.), Thursday next week's agenda, Friday a photo. Each format has default networks: our carousels go to Instagram only. As of October 12, 59 posts in the queue target LinkedIn, Instagram and X at once.

For a SaaS, pick other formats (customer story, feature, product metric) and give each one a source that produces candidates without you.

Step 1: generate the queue three weeks ahead

Fill the empty slots

Our queue settings fit in a handful of keys:

{
  "timezone": "Europe/Paris",
  "min_lead_hours": 3,
  "x_char_limit": 280,
  "spacing_minutes": 45,
  "formats": {
    "carousel": { "weekday": 0, "time": "12:00", "platforms": ["instagram"] },
    "quote":    { "weekday": 1, "time": "12:00", "platforms": ["linkedin", "instagram", "twitter"] },
    "tool":     { "weekday": 2, "time": "12:00", "platforms": ["linkedin", "twitter"] }
  }
}

On each pass, the agent spots the empty slots in the next three weeks and pulls the next candidate from that format's source. An exhausted source produces a "skipped" post with its reason, for example "Quote bank exhausted". You see the gap three weeks before the date.

Skip past slots

Two timing rules prevent surprise posts. The agent never schedules a slot less than three hours away (min_lead_hours). And a post whose slot passes without approval switches to "skipped" the next time the queue is read, with the reason "slot passed without approval". As of October 12, our queue holds 8 skipped posts. Without approval, nothing goes out.

Step 2: rewrite the copy for each network

You write one source caption with the link in plain text. At scheduling time, a script produces the copy for each network and puts the link in the one place where it works.

Recreated screenshot: a fictional source caption rewritten for LinkedIn, X and Instagram

LinkedIn: the link goes in the first comment

Since October 2, 2026, no link goes into the body of a LinkedIn post. The sentence carrying the link goes into the first comment, and the post points to it. On the API side, Zernio receives the LinkedIn copy in customContent and the comment in platformSpecificData.firstComment. The Zernio documentation on first comments gives roughly 1,250 characters for a LinkedIn comment, posted a few seconds after the post.

A LinkedIn post body can run to 3,000 characters, but the "see more" fold lands around 210: your idea has to fit before it.

X: one tweet of 280 weighted characters

X gets its own copy, separate from LinkedIn and Instagram. Our rule since October 3, 2026: one tweet of 280 characters at most, never a thread. An X post is therefore one message, or two when the link goes in the first reply.

The trap is in the counting. According to the official X documentation on counting characters, every URL counts as 23 characters regardless of length, and an emoji counts as 2. Our script reproduces that weighting:

def x_length(text: str) -> int:
    """Length as counted by X: each URL counts as 23, emoji and non-Latin symbols count as 2."""
    text = (text or "").strip()
    n = 0
    for part in X_URL.split(text):
        n += sum(_x_weight(c) for c in part)
    return n + 23 * len(X_URL.findall(text))

With a plain len(), a 275-character tweet that weighs 290 for X gets through your review, then fails on publishing day, three weeks after your "ok".

Instagram: the link in bio

A link in an Instagram caption isn't clickable. The script removes it and ends the caption with a pointer to the link in bio. The caption fits in 2,200 characters, with 5 hashtags at most, and the fold lands around 125 characters.

LinkedIn, X and Instagram compared: length, link and media

Step 3: block errors with scripts

Before you read anything, deterministic scripts check every post. As long as a post carries an error, it can't be approved or scheduled.

Length and media checks

Our scripts block approval in six cases:

  1. The tweet or its reply exceeds 280 weighted characters.
  2. The X copy contains a thread (--- separator).
  3. The X copy is missing for a format with no default X copy.
  4. The X post carries more than 4 images, or an image over 5 MB.
  5. A PDF targets a network other than LinkedIn (document carousels only exist there).
  6. The post targets no network, or an unknown one.

Each message says what to do: "X: X copy missing, write it in the X Text field (one tweet of 280 characters at most)".

Checking for writing tics

Every caption, in French or English, goes through our anti-tic script: two-step corrections, em-dashes, empty phrases, objects that act on their own. Since September 30, 2026, we require zero BLOCK results, otherwise approval and scheduling stay locked. Our review queue shows the result under the caption.

For a SaaS, the minimal equivalent is a list of banned patterns as regular expressions and an exit code of 1 as soon as one matches. Our tutorial on how to write a LinkedIn post with AI covers this check in detail.

45 minutes between two posts on the same network

Two posts on the same network stay at least 45 minutes apart. Each post keeps a target time. When there's a conflict, the post takes the nearest free window on the same day, in this order: +45, -45, +90, -90 minutes. The calculation runs every time the queue is saved, and the post returns to its target time as soon as the conflict clears.

A real excerpt from a post's history:

spaced  moved to 1:15 p.m. (target 12:30 p.m.): another post is on this network less than 45 min away
spaced  back to its target time, 12:30 p.m.

Spacing leaves posts already at Zernio alone: they keep their time.

Recreated screenshot of a post in our review queue, moved by 45 minutes

Step 4: approve or reject each post

Our review queue shows the exact copy for each network, the first comment, the media, the time and the checks. You have three answers: approve, reject, or request a change.

Tie approval to the exact copy

Your approval applies to a specific text. If anyone edits the caption, the media, the X copy or the first comment of an approved post, it goes back to to_review. A simple time change keeps the approval.

The second version of our script goes further: it ties approval to a fingerprint of the copy and the image files, and you approve with a 6-character review code derived from that fingerprint:

python3 scripts/pubqueue.py approve offre-annuelle.linkedin --by <votre-nom> --code d84e8f

If the copy changed since you read it, the code no longer matches and the approval fails. A status typed by hand into the file goes back to review at scheduling time.

We also approve in batches: 6 carousels at once on October 8, each one run through the checks again.

Reject to move the queue forward

"No, next" rejects the post. The next post of the same format takes its slot, the posts after it move up a week, and the last freed slot gets the next candidate from the source. A rejected post never comes back on its own.

Rejecting leaves the calendar intact. As of October 12, we have rejected 3 posts.

Before and after a rejection: the following posts move up a week

A change request launches the format's agent. An example from our history: "Different quote in the caption, shorter (under 100 characters), still in English." The agent rewrites, reruns the checks and puts the post back in to_review.

Keep approval out of the agent's reach

On October 1, 2026, we asked the agent to add carousels to the queue. The slide content had received an "ok" earlier in the conversation. The agent read that "ok" as approval to publish and moved 7 carousels to approved. We reopened all 7 with the note "approval reverted: only the user approves".

Since then, the rule lives in both the agent's instructions and the code: the agent adds posts in to_review and stops. In the second version, the approve command rejects agent names and exits with an error (code 3) when nobody types the code.

Step 5: schedule with the Zernio API

To schedule our LinkedIn, Instagram and X posts, we go through Zernio, a publishing API that also covers about ten other networks. In our setup, an approval triggers scheduling immediately.

The scheduling request

The script first uploads each media file to Zernio's storage through a presigned URL (POST /media/presign, then a PUT of the file). It then creates the post:

{
  "content": "<source caption>",
  "mediaItems": [{ "type": "image", "url": "<Zernio storage URL>" }],
  "platforms": [
    { "platform": "linkedin", "accountId": "<LinkedIn account>",
      "customContent": "<LinkedIn copy without link>",
      "platformSpecificData": { "firstComment": "<sentence + link>" } },
    { "platform": "twitter", "accountId": "<X account>",
      "customContent": "<tweet>",
      "platformSpecificData": { "threadItems": ["<tweet>", "<reply + link>"] } },
    { "platform": "instagram", "accountId": "<Instagram account>",
      "customContent": "<caption + pointer to link in bio>" }
  ],
  "scheduledFor": "2026-10-20T12:00:00",
  "timezone": "Europe/Paris"
}

The Idempotency-Key header combines the post ID and its slot, so a double click or a retry after a network drop won't create two posts. On cost, X bills each post per API call through Zernio, and that cost weighs on which networks each format uses.

The production switch

The queue has a switch, live. Set to false, all scheduling stops with the message "auto-publishing not in prod". Handy while you're tuning things, dangerous afterward.

Three pitfalls from our AI social media agent

Five days of silent "approved"

Until October 3, 2026, the switch stayed at false. Our review queue showed "approved" and nothing reached Zernio. A photo approved on September 30 never went out on October 2. For 5 days, we assumed "approved" meant "published".

We switched the queue to production on October 3, then scheduled the already-approved posts one by one. If your tool has a test mode, display it prominently on the review screen.

The duplicate posted by hand

One of our 3 rejections carries the note "already published on Instagram on 09/26". Someone had posted the quote by hand before the queue was set up, and the agent could only see its source. Before plugging in an agent, list what has already gone out on each account and mark it as used in the source.

The connector linked to another account

Claude's Zernio MCP connector answered "No accounts connected". We wrongly concluded that none of our accounts were on Zernio. The connector was pointing to a different, empty Zernio account, while the script's API key could see LinkedIn, Instagram and X just fine. Check your accounts with the key that actually publishes.

Checklist of the ten safeguards in our AI social media agent

Ten days of queue in numbers

As of October 12, 2026, after ten days in production:

Metric Value
Posts created in the queue 90
Recorded approvals 81
Posts scheduled at Zernio 73
Last scheduled slot April 20, 2027
Rejected posts 3
Skipped posts 8
Posts to review 5
Spacing shifts 5

Weekly quotes and photos make up most of the 73 scheduled posts. Zernio had no best-time data at the start, so we'll revisit our posting times after six weeks of stats.

To decide what goes into the queue, our article on founder-led content strategy lays the groundwork, and the LinkedIn carousel with AI tutorial produces one of the formats. Our overview of AI marketing agents shows where this agent sits in the chain.

A well-tuned AI social media agent takes over the mechanics and leaves you the one decision that puts your name on the line.

FAQ

Can an AI agent publish to social media on its own?

Technically yes, with an API like Zernio. In our setup, only a human approves, and a post with no approval by the time its slot arrives is marked "skipped".

Which tasks should you hand to an AI social media agent?

Filling the calendar, rewriting for each network, placing links, counting characters, spacing posts and calling the API. Keep topic selection and the approval of each post for yourself.

Where should the link go on each network?

In the first comment on LinkedIn, in the first reply on X, in the bio on Instagram. Keep the link in plain text in the source. A script moves it at scheduling time.

How does X count characters?

A URL counts as 23 characters regardless of length, an emoji counts as 2, and the limit is 280. A Python len() gets it wrong as soon as there's a long link or an emoji.

How far ahead should you schedule posts?

We fill the queue three weeks ahead, with a minimum lead time of three hours before a slot. That lead time gives you room to reject a post without leaving a gap.

Do you need a paid tool to publish through an API?

You need a service that holds the networks' authorizations. We use Zernio, billed by usage, and X also bills each post per API call. You connect your accounts once, then the script publishes with an API key.