Agent Playbook, build tutorial

How to Build an AI Agent for Social Media

A walkthrough of how to build a social media agent that turns one brief into a full posting plan: it plans the calendar, drafts each post adapted to its platform, suggests the visuals, and reports on what worked, while a person approves before anything publishes. Every code step is shown in three frameworks, Google ADK, the Claude SDK, and LangGraph, so you can build it on the stack your team already knows. The code here is the agent's core logic; standing it up in production also means adding the setup, integrations, and hardening around it.

Why social media eats a team's week

Posting consistently is a grind. Someone has to think up topics, write a different version for each network, find or make a visual, schedule it, and then remember to look at how it did. When the week gets busy the calendar goes quiet, the voice drifts between whoever happened to post, and the same caption gets copied across platforms where it reads wrong on at least one of them.

A social media agent does the first pass. From one brief it lays out a calendar, drafts each post for its platform in your brand voice, suggests the visual, and pulls the numbers back in to learn what works, so your team reviews and approves instead of starting from a blank page every day. The one thing it never does is publish on its own. For long-form pieces behind the posts, this pairs with the content playbook, and for replies that land in your inbox, the email and inbox playbook.

Pick a framework: ADK, Claude SDK, or LangGraph

You do not build the agent loop from scratch. A framework gives you the moving parts, and you supply the logic: a step is a model plus an instruction plus a typed schema or a few tools. The code tabs on the build steps show the same plan, draft, and report flow three ways.

Google ADK composes the steps with a SequentialAgent and a Runner, the Claude SDK drives a tool-use loop, and LangGraph builds an explicit graph. The brief intake, the scheduling, and the approval guardrail are deterministic and identical in all three; only the orchestration and the model calls differ.

The architecture

Every campaign flows through one loop: the brief comes in and a calendar is planned, each post is drafted and given a visual, then scheduled. Nothing publishes until a person approves; once it does, the agent pulls metrics back in to inform the next plan. Guardrails for idempotency, brand safety, approval, and audit wrap the whole thing.

1. Brief and brand voice goal, audience, dates 2 to 3. Plan and draft calendar + per-platform posts 4. Attach visuals image brief or library 5. Schedule Meta, LinkedIn, X, Buffer 6. Approve and publish a person taps approve 7. Report reach, likes, clicks 8. Run and monitor scheduled, audited Guardrails brand safety never auto-publish audit log approve once live learn, next plan feedback loop

Before you build: prerequisites

Inputs and access

A campaign brief and a brand-voice profile, plus connected accounts for the networks you post to (Meta, LinkedIn, X) or a scheduler suite.

Systems to connect

A model API key (Gemini, Claude, or both), your social accounts or scheduler, an approved asset library, and an image model only if you opt into generation.

Governance

Who approves posts, your brand-safety and disclosure rules, consent for any personal data, and which topics stay out of scope.

Setup: install and keys

Install the packages and set your Gemini key. That is enough to run the runnable file below, which plans a short calendar and drafts posts for a sample brief locally. For production you also connect, with each platform's credentials, your social accounts or scheduler and your asset library.

Shell (install and key)
# Python 3.10 or newer
python -m venv venv && source venv/bin/activate

# The runnable path below uses Google ADK + Gemini:
pip install google-adk google-genai pydantic

# Your Gemini key from aistudio.google.com/apikey:
export GEMINI_API_KEY="your-key-here"

The stack, and why each piece

Layer Pick Why
Brief and brand voice A short campaign brief plus a brand-voice profile (tone, do and do-not words, examples) Everything downstream starts from one input. The brief sets the goal, the audience, and the dates; the brand-voice profile keeps every draft sounding like you, not like a generic model.
Planner A model (Gemini 2.5 Flash, Claude) over the brief Turns the brief into a calendar: topics laid across dates and platforms, so a month of posting is planned in one pass instead of decided ad hoc each morning. The code tabs show this three ways.
Per-platform drafter A model with the brand voice and per-network rules Writes each post adapted to its platform, length, tone, and hashtags tuned for LinkedIn, Instagram, or X, because the same caption does not work everywhere. Drafts are for review, never published on their own.
Visuals An image brief plus an asset library, or image generation if you opt in By default the agent drafts the caption and writes an image brief or picks from your approved asset library. If you turn on image generation, it says so plainly and a person still reviews the result.
Scheduler and publishing Meta Graph API, LinkedIn API, X API, or a suite (Buffer, Hootsuite) Schedules the approved post to the right account at the right time. Publishing happens only after a human approves; the agent never auto-publishes.
Analytics and audit Each platform's insights API plus an audit log Pulls likes, reach, and clicks back in to learn what works, and records every plan, draft, approval, and publish so there is a trail behind each post.

Build it, step by step

The plan, draft, and assemble steps show the same logic in Google ADK, the Claude SDK, and LangGraph. Use the tabs to switch. The brief intake, visuals, scheduling, approval, and reporting steps are deterministic Python and identical everywhere. These are the building blocks, and they call your own systems (the social accounts, the asset library) by name; the complete file you can run today is in "Put it together" below.

1

Take the brief and brand voice

Start with the input, not the cleverness. The agent reads a short campaign brief, the goal, the audience, the dates, the platforms, and a brand-voice profile that lists your tone, your do and do-not words, and a few example posts. It normalises both into one structured object that every later step reads from, and keys the run on a campaign id so a re-run never duplicates a plan. Deterministic, and the same in every framework.

Python (brief intake)
from dataclasses import dataclass, field

@dataclass
class Campaign:
    goal: str
    audience: str
    start: str                       # ISO date, e.g. "2026-07-01"
    days: int
    platforms: list[str]             # ["linkedin", "instagram", "x"]
    voice: str                       # tone + do/do-not words + examples
    campaign_id: str = ""

def load_campaign(brief: dict, brand_voice: str) -> Campaign:
    c = Campaign(goal=brief["goal"], audience=brief["audience"],
                 start=brief["start"], days=brief["days"],
                 platforms=brief["platforms"], voice=brand_voice,
                 campaign_id=brief["id"])     # id makes the run idempotent
    return c
# One structured object feeds every later step; no model call needed here.
2

Plan the calendar: topics across dates and platforms

A month of posting is a lot of small decisions, so the agent makes them in one pass. It asks the model to turn the brief into a calendar: a list of posts, each with a topic, a date, and a target platform, spread sensibly across the campaign window. A typed schema keeps the output as data the scheduler can use, not prose someone has to re-key. The tabs show the same planning in Gemini, Claude, and LangChain; the shape never changes.

from google import genai
from google.genai import types
from pydantic import BaseModel
client = genai.Client()

class Post(BaseModel):
    topic: str; date: str; platform: str

class Calendar(BaseModel):
    posts: list[Post]

def plan(c) -> Calendar:
    res = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[f"Plan {c.days} days of posts for {c.platforms} on goal "
                  f"'{c.goal}' for {c.audience}, starting {c.start}."],
        config=types.GenerateContentConfig(
            response_mime_type="application/json", response_schema=Calendar))
    return res.parsed                # a typed Calendar object
from anthropic import Anthropic
client = Anthropic()
SCHEMA = {"type": "object", "properties": {
    "posts": {"type": "array", "items": {"type": "object", "properties": {
        "topic": {"type": "string"}, "date": {"type": "string"},
        "platform": {"type": "string"}}, "required": ["topic", "date", "platform"]}}},
    "required": ["posts"]}

def plan(c) -> dict:
    res = client.messages.create(model="claude-opus-4-8", max_tokens=2048,
        tools=[{"name": "save_calendar", "input_schema": SCHEMA}],
        tool_choice={"type": "tool", "name": "save_calendar"},
        messages=[{"role": "user", "content":
            f"Plan {c.days} days of posts for {c.platforms} on goal "
            f"'{c.goal}' for {c.audience}, starting {c.start}."}])
    return res.content[0].input
from langchain_google_genai import ChatGoogleGenerativeAI
from pydantic import BaseModel

class Post(BaseModel):
    topic: str; date: str; platform: str

class Calendar(BaseModel):
    posts: list[Post]

planner = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash").with_structured_output(Calendar)

def plan(c) -> Calendar:
    return planner.invoke(
        f"Plan {c.days} days of posts for {c.platforms} on goal "
        f"'{c.goal}' for {c.audience}, starting {c.start}.")
3

Draft each post, adapted per platform

The same caption does not work on every network, so the agent drafts each post for its platform: tighter and hashtag-light for LinkedIn, punchy with a few tags for Instagram, short and within the character limit for X. It writes in your brand voice using the profile from step 1. Each draft is a starting point for review, never something the agent publishes itself. The tabs show the same per-platform draft three ways.

from google import genai
client = genai.Client()
RULES = {"linkedin": "professional, 1 to 2 short paragraphs, 0 to 2 hashtags",
         "instagram": "warm and visual, 3 to 8 relevant hashtags",
         "x": "punchy, under 280 characters, 1 to 2 hashtags"}

def draft_post(topic: str, platform: str, voice: str) -> str:
    return client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[f"Brand voice: {voice}\nWrite a {platform} post about "
                  f"'{topic}'. Style: {RULES[platform]}. It is for review, "
                  f"not to be published automatically."]).text
# The return value is a draft shown to a person, never published by the agent.
from anthropic import Anthropic
client = Anthropic()
RULES = {"linkedin": "professional, 1 to 2 short paragraphs, 0 to 2 hashtags",
         "instagram": "warm and visual, 3 to 8 relevant hashtags",
         "x": "punchy, under 280 characters, 1 to 2 hashtags"}

def draft_post(topic: str, platform: str, voice: str) -> str:
    res = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
        messages=[{"role": "user", "content":
            f"Brand voice: {voice}\nWrite a {platform} post about '{topic}'. "
            f"Style: {RULES[platform]}. For review only, not to be published."}])
    return res.content[0].text
from langchain_google_genai import ChatGoogleGenerativeAI
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")   # or ChatAnthropic(...)
RULES = {"linkedin": "professional, 1 to 2 short paragraphs, 0 to 2 hashtags",
         "instagram": "warm and visual, 3 to 8 relevant hashtags",
         "x": "punchy, under 280 characters, 1 to 2 hashtags"}

def draft_post(topic: str, platform: str, voice: str) -> str:
    return llm.invoke(
        f"Brand voice: {voice}\nWrite a {platform} post about '{topic}'. "
        f"Style: {RULES[platform]}. For review only, not to be published.").content
4

Attach or suggest visuals, honestly

Be plain about what this step does. By default the agent does not invent pictures: it writes an image brief describing what the visual should show, and it can pick a matching asset from your approved library by tag. If you choose to turn on image generation, the agent calls an image model and labels the output as generated, and a person still reviews it before it goes near a post. Either way, a human approves the visual. Deterministic, and the same in every framework.

Python (image brief or library pick)
def attach_visual(post: dict, asset_library, generate: bool = False) -> dict:
    # Default: write an image brief and try the approved asset library by tag.
    post["image_brief"] = f"Visual for: {post['topic']}, on-brand, {post['platform']}"
    match = asset_library.find(tags=[post["topic"], post["platform"]])
    if match:
        post["image"] = match.url            # reuse an approved asset
        post["image_source"] = "library"
    elif generate:                           # only if you opted in
        post["image"] = image_model.create(post["image_brief"])
        post["image_source"] = "generated"   # labelled clearly for review
    else:
        post["image_source"] = "brief_only"  # a person sources the image
    return post
# Captions plus an image brief by default; generation only when you turn it on.
5

Schedule via the platform or scheduler API

Once a post is approved, scheduling is a plain API call. The agent posts the approved caption and visual to the right account at the planned time through the Meta Graph API, the LinkedIn API, the X API, or a suite like Buffer. It records the scheduled item against the campaign so the calendar stays the single source of truth. Scheduling an approved post is safe; the approval that gates it is the next step. Deterministic, and the same in every framework.

Python (schedule approved post)
def schedule(post: dict, account) -> dict:
    # post is already approved; this only places it on the calendar.
    ref = scheduler.create(
        account_id=account.id,
        platform=post["platform"],
        text=post["text"],
        media=post.get("image"),
        publish_at=post["date"])             # the planned time
    post["scheduled_ref"] = ref
    ledger.record(post, status="scheduled")
    return post
# A queued, approved post; nothing is published until a person approves below.
6

Publish only on human approval, never auto-publish

This is the guardrail that makes the whole thing safe for a brand. Drafts and scheduled items do not go live on their own; they sit in an approval queue where a person reads the post, sees the visual, and approves with one tap, edits, or discards. Only on approval does the agent publish. Nothing reaches your audience without a human behind it, which is the line that separates a helpful assistant from a brand-risk machine. Deterministic, and the same in every framework.

Python (approve, never auto-publish)
def queue_for_approval(post: dict) -> None:
    approval_queue.add(post)                 # awaits a human; never auto-posts

def on_approval(post: dict, final_text: str) -> None:
    publisher.publish(platform=post["platform"], text=final_text,
                      media=post.get("image"))       # only after approval
    ledger.record(post, status="published")
    audit.log("published", post["id"], final_text)
# The agent drafts, schedules, and queues; publishing happens only on approval.
7

Report on engagement and learn what works

After posts go live, the loop closes. The agent pulls likes, reach, comments, and clicks from each platform's insights API, attributes them back to the topic and the network, and summarises what is working so the next plan leans on it. Pulling and aggregating metrics is straight integration code against your own accounts, deterministic and the same in every framework. The summary it produces becomes context for the next planning pass.

Python (pull metrics, feed back)
def report(campaign_id: str) -> dict:
    rows = []
    for post in ledger.published(campaign_id):
        m = insights.fetch(post["platform"], post["scheduled_ref"])
        rows.append({"topic": post["topic"], "platform": post["platform"],
                     "reach": m["reach"], "likes": m["likes"],
                     "clicks": m.get("clicks", 0)})
    summary = aggregate_by_topic(rows)       # which topics and networks won
    ledger.save_report(campaign_id, summary) # context for the next plan
    return summary
# Metrics pulled per post, aggregated by topic, and fed into the next calendar.
8

Assemble the run, with brand safety and approval guardrails

The pieces run on each campaign. ADK composes plan, draft, and report under a SequentialAgent and a Runner, the Claude SDK runs them in a tool-use loop, and LangGraph builds an explicit plan, draft, schedule graph. Whichever you pick, the same guardrails apply: the campaign id makes every run idempotent, the agent never publishes without approval, an on-brand check screens every draft, posting respects each platform's rate limits, and every plan, draft, approval, and publish is written to an immutable audit log.

from google.adk.agents import SequentialAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService

social_pipeline = SequentialAgent(name="social_pipeline",
    sub_agents=[planner, drafter, reporter])   # each an LlmAgent with the tools

runner = Runner(agent=social_pipeline, app_name="social",
                session_service=InMemorySessionService())

def guard(post: dict) -> str | None:
    if store.seen(post["campaign_id"]):   return "already_planned"  # idempotent
    if not on_brand(post["text"]):        return "needs_review"     # brand check
    if rate_limited(post["platform"]):    return "wait"             # rate limit
    return None
# Run per campaign via cron / Cloud Scheduler. Publishing always needs approval.
from anthropic import Anthropic
client = Anthropic()
TOOLS = [plan_tool, draft_tool, schedule_tool, queue_tool]   # JSON schemas

def run_social(messages: list):
    while True:
        resp = client.messages.create(model="claude-opus-4-8", max_tokens=2048,
                                      tools=TOOLS, messages=messages)
        if resp.stop_reason != "tool_use":
            return resp
        messages.append({"role": "assistant", "content": resp.content})
        for b in resp.content:
            if b.type == "tool_use":
                out = dispatch(b.name, b.input)   # no publish tool: drafts only
                messages.append({"role": "user", "content": [
                    {"type": "tool_result", "tool_use_id": b.id, "content": str(out)}]})
from langgraph.graph import StateGraph, START, END

g = StateGraph(dict)
g.add_node("plan",     lambda s: {"calendar": plan(s["campaign"])})
g.add_node("draft",    lambda s: {"posts": [draft_post(p.topic, p.platform,
                                  s["campaign"].voice) for p in s["calendar"].posts]})
g.add_node("schedule", lambda s: {"queued": [queue_for_approval(p) for p in s["posts"]]})
g.add_edge(START, "plan")
g.add_edge("plan", "draft")
g.add_edge("draft", "schedule")
g.add_edge("schedule", END)
social_pipeline = g.compile()      # invoke per campaign; posts queue for approval

Put it together: run it end to end

Here is a runnable file. It plans a short calendar from a sample brief, drafts a post per platform, and writes an image brief for each, and it does not publish anything. The brief is inline text; production reads it from your campaign source, as in the build steps. Save it as main.py and run python main.py.

Python (full runnable file, ADK)
# main.py  --  run:  python main.py
# A runnable reference: plans a short calendar from a sample brief, drafts one
# post per platform, and suggests an image brief. It does NOT publish anything
# (publishing always needs approval). The brief is inline; production reads it
# from your campaign source, as in the build steps.
import asyncio
from google import genai
from google.genai import types
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner

client = genai.Client()                       # reads GEMINI_API_KEY

# ---- a sample brief (replace with a real campaign brief) ----
SAMPLE_BRIEF = """Goal: announce our new GST invoicing feature for small shops.
Audience: Indian SME owners and their accountants.
Dates: 3 days starting 2026-07-01. Platforms: linkedin, instagram, x.
Brand voice: warm, plain, practical. Avoid hype words like 'revolutionary'."""
# -------------------------------------------------------------

RULES = {"linkedin": "professional, 1 to 2 short paragraphs, 0 to 2 hashtags",
         "instagram": "warm and visual, 3 to 8 relevant hashtags",
         "x": "punchy, under 280 characters, 1 to 2 hashtags"}

def plan_calendar(brief: str) -> str:
    """Turn the brief into a calendar as JSON (a list of posts)."""
    return client.models.generate_content(
        model="gemini-2.5-flash",
        contents=["Plan a posting calendar from this brief as JSON with key "
                  "posts (list of {topic, date, platform}).\n" + brief]).text

def draft_post(topic: str, platform: str, voice: str) -> str:
    """Draft one on-brand post for a platform. For review only; not published."""
    return client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[f"Brand voice: {voice}\nWrite a {platform} post about "
                  f"'{topic}'. Style: {RULES.get(platform, 'concise')}. It is "
                  f"for review, not to be published automatically."]).text

def suggest_visual(topic: str, platform: str) -> str:
    """Write an image brief for a person or asset library to source from."""
    return f"Image brief for {platform}: an on-brand visual showing '{topic}'."

agent = LlmAgent(
    name="social_agent", model="gemini-2.5-flash",
    instruction=("Call plan_calendar on the brief, then for two of the planned "
                 "posts call draft_post and suggest_visual. Report the calendar, "
                 "the drafts, and the image briefs. Make clear every post is "
                 "queued for approval and nothing is published."),
    tools=[plan_calendar, draft_post, suggest_visual])

async def main():
    runner = InMemoryRunner(agent=agent, app_name="social")
    session = await runner.session_service.create_session(app_name="social", user_id="demo")
    msg = types.Content(role="user",
                        parts=[types.Part(text=f"Plan and draft for this brief:\n{SAMPLE_BRIEF}")])
    async for event in runner.run_async(user_id="demo", session_id=session.id, new_message=msg):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    asyncio.run(main())

The agent reports a small calendar of topics across the three platforms, two drafted posts adapted to their networks, and an image brief for each, all queued for approval. The exact wording is model-generated, so it varies run to run; publishing is never automatic.

The approval console

A person sees one screen: the planned calendar, the drafted post and its suggested visual, and a single approve action before anything publishes.

Content calendar, awaiting approval THIS WEEK (3) Tue, LinkedInGST feature launch Wed, Instagram3 ways it saves time Thu, Xquick tip thread DRAFT POST PlatformLinkedIn Brand checkon-brand Filing GST used to mean alate night. Our new invoicingfeature does it in minutes ... Hashtags2 suggested VISUAL (suggested) Image briefon-brand, GST feature Sourcelibrary or brief Nothing publishes until you approve. Approve and schedule Edit

Build, buy, or no-code

Approach Best for Effort Cost Control
Custom agent (build in-house) You want your own brand voice, planning rules, and account wiring, with approval and the data in-house High Build cost + API and model usage Full
Scheduler suite (Buffer, Hootsuite, Sprout Social) Planning, scheduling, and reporting in one tool, fast start, you accept their drafting and rules Low Subscription per seat or channel Medium
No-code (n8n or Make with social nodes) A few simple flows, low volume, a quick pilot Low Cheap, but brittle as the brand rules grow Low

Brand safety and approval

The defining safety choice is that the agent never auto-publishes. Planning, drafting, and suggesting visuals are low-risk and reversible; a public post is not, so it always waits for a person who reads the caption, sees the visual, and approves. Every draft is screened by an on-brand check first, so what reaches the queue already fits your voice and your do-not list, and a reviewer makes the final call.

Beyond approval, the agent follows each platform's policies and discloses ads and paid partnerships as those platforms require, and it does not post anyone's personal data without consent, in line with the DPDP Act 2023, whose core obligations phase in through 2027. Sensitive or off-brief topics stay out of scope, and every plan, draft, approval, and publish is written to an immutable audit log so there is a record behind each post.

The numbers

These are directional, not promises, and depend on how much you post and how much editing the drafts need. The point is the shape of the change: less time planning and writing, a steadier cadence, a better per-platform fit, and a feedback loop that was rarely closed by hand.

Metric Manual Agent
Time to plan a month A long planning session, then drafting each post one at a time as the date nears A full calendar drafted from one brief in a single pass, so the team reviews instead of starting from blank
Consistency of posting Gaps when the week gets busy, and tone that drifts between people A steady cadence with on-brand drafts every time, so the calendar stays full and the voice stays steady
Per-platform fit The same caption copied across networks, so it reads wrong somewhere Each post adapted to its platform, length, tone, and hashtags, drafted for that network
Learning from results Engagement is glanced at, rarely fed back into the next plan Metrics pulled in and summarised, so the next calendar leans on what actually worked

Time saved depends on posting volume and how much the drafts need editing. Figures are ranges that vary by team, not guarantees.

What makes it fail

  • !Letting it auto-publish, so an off-brand or wrong post goes public with no human check.
  • !One caption copied across every network instead of drafting per platform.
  • !No campaign-id idempotency, so a re-run plans and queues the same campaign twice.
  • !Passing off generated images as real photos, or skipping ad and partnership disclosure.
  • !Ignoring platform rate limits, so scheduled posts are throttled or rejected.

A safe rollout

  1. Start with planning and drafting only, no scheduling, on one brand and one platform.
  2. Add per-platform drafting and visual suggestions in approve-only mode, and tune the voice.
  3. Turn on scheduling with publishing still gated on a person's approval.
  4. Expand to more platforms and brands, with an engagement dashboard feeding the next plan.

FAQs

General FAQs

Everything you need to know about the service and how it works. Can’t find an answer? Mail us at info@galific.com

  • Does it post to social media on its own?
    No, and this is the most important design choice. The agent plans the calendar, drafts each post, suggests visuals, and queues everything, but every post goes into an approval queue where a person reads the caption, sees the visual, and approves, edits, or discards it. Only on approval does it publish. Nothing reaches your audience without a human behind it, because a bad post is a public, lasting brand risk in a way an unsent email is not.
  • Which platforms does it support?
    It works with the major networks through their APIs: LinkedIn, Instagram and Facebook via the Meta Graph API, and X, and it can also drive a scheduler suite like Buffer or Hootsuite if you already use one. Each post is drafted for the platform it targets, so the LinkedIn version and the X version of the same topic read differently rather than being one caption copied everywhere.
  • How does the planning step actually work?
    The agent takes your brief, the goal, the audience, the dates, and the platforms, and asks the model to return a calendar as structured data: a list of posts, each with a topic, a date, and a target platform, spread across the campaign window. Because the output is a typed schema rather than prose, the scheduler can use it directly, and a person reviews and adjusts the calendar before any drafting begins.
  • Does it generate the images, and is that honest?
    By default it does not invent pictures. It drafts the caption and writes an image brief describing what the visual should show, and it can pick a matching asset from your approved library. If you choose to turn on image generation, the agent calls an image model and labels the result as generated so no one mistakes it for a real photo, and a person still reviews every visual before it is attached. We are plain about this because pretending an agent sources perfect images on its own would be misleading.
  • Will the posts actually sound like our brand?
    They are written from a brand-voice profile you supply: your tone, your do and do-not words, and a few example posts, so the drafts aim at your voice rather than a generic one. They are usually a strong starting point rather than a finished post, which is why a person always reviews before publishing. The more examples and guidance you give, the closer the voice gets, and the approval step catches anything off before it goes live.
  • How does it report on engagement?
    After posts publish, it pulls likes, reach, comments, and clicks from each platform's insights API and attributes them back to the topic and the network, then summarises what worked. That summary becomes context for the next planning pass, so the calendar leans on the posts that actually performed rather than on guesses. The figures come straight from the platforms, not from the agent.
  • Which framework should I use: ADK, the Claude SDK, or LangGraph?
    Whichever your team already runs, because the agent logic is identical in all three. The code tabs show the same plan, draft, and report flow in Google ADK, the Anthropic SDK, and LangGraph. ADK and LangGraph are model-agnostic, so you can run Gemini or Claude under either; the scheduling, the approval gate, and the guardrails are the same Python regardless.
  • Should I build a custom agent or use a scheduler suite?
    Use a suite like Buffer, Hootsuite, or Sprout Social for planning, scheduling, and reporting with little setup when you accept their drafting and rules. Build, or have it built, when you need your own brand voice, your own planning logic, wiring into your accounts and asset library, and the data in-house. Teams often start with a suite for scheduling and build a custom agent for the drafting and brand-voice layer. See the comparison table above.
  • What does it cost to run, and how fast is payback?
    Running cost is mostly model and API usage plus hosting, which is small against the hours a team spends planning and writing posts each month. Because the agent drafts a whole calendar from one brief and the team reviews instead of starting from blank, the saving can show up quickly in time recovered and a steadier posting cadence. As with any tool, the gain depends on how much you post and how much editing the drafts need.
  • Can it write posts in Indian languages?
    The models read and write in English and major Indian languages, so a campaign can be drafted in Hindi or as a bilingual mix where that fits your audience. Quality varies with the language and the topic, and the human approval step before any publish means an awkward draft is caught and fixed rather than posted. For a multi-language brand, supplying example posts in each language helps the voice hold up.
  • What should this agent not do?
    It should not auto-publish, post about sensitive or political topics outside its brief, run paid ads or partnerships without the required disclosure, or include anyone's personal data without consent. It drafts and schedules; a person owns the decision to publish. Keeping those lines clear is what makes it safe to point at a live brand account rather than a risk to it.

Want this built and running in your stack?

Galific designs, builds, and runs social media agents like this on ADK, the Claude SDK, or LangGraph, wired into your accounts and your brand voice, with a person approving before anything publishes. Or explore the ready-made versions in our agent suite.