What it does
social-media-agent takes a URL, scrapes its content, generates a marketing report, drafts a Twitter/LinkedIn post, and schedules it — all through a LangGraph state machine with human-in-the-loop review. It is built and maintained by the LangChain team and sits at around 2,400 stars.
Why I starred it
Most "AI social media" tools stop at text generation. This one builds the entire pipeline: content ingestion, link verification across platforms (GitHub, YouTube, Twitter, Reddit, Luma), report generation, post drafting, image selection, human approval via an interrupt-based inbox, and actual scheduling through Arcade or native API auth. It is a real reference architecture for how LangGraph agents look in production.
How it works
The core lives in src/agents/generate-post/generate-post-graph.ts. It is a StateGraph with 11 nodes wired through conditional edges. The flow:
- Auth passthrough — validates social media credentials
- Verify links subgraph — a separate
StateGraphinsrc/agents/verify-links/verify-links-graph.tsthat fans out using LangGraph'sSendprimitive to route each URL to a type-specific verifier (YouTube, GitHub, Twitter, Reddit, Luma, or general web scraping via FireCrawl) - Generate content report — calls Claude Sonnet with the scraped page contents, parses the result from
<report>XML tags - Generate post — another Claude Sonnet call with the report, few-shot examples, and structure instructions
- Condense loop — if the post exceeds 280 characters, it re-enters a condense node up to 3 times
- Image pipeline — finds, generates, and re-ranks images via a sub-graph in
src/agents/find-and-generate-images/ - Human node — calls
interrupt()from@langchain/langgraphto pause execution and surface the draft in Agent Inbox - Schedule — posts to Twitter/LinkedIn through Arcade or direct OAuth
The link verification fan-out is the most interesting pattern. In verify-links-graph.ts, the routeLinkTypes function maps each input URL to a Send object targeting the right verifier node:
function routeLinkTypes(state: typeof VerifyLinksGraphAnnotation.State) {
return state.links.map((link) => {
const type = getUrlType(link);
if (type === "twitter") {
return new Send("verifyTweetSubGraph", { link });
}
if (type === "github") {
return new Send("verifyGitHubContent", { link });
}
// ... youtube, reddit, luma, general
return new Send("verifyGeneralContent", { link });
});
}
This runs all verifiers in parallel. Each one extracts page contents and relevant links, which get merged back into the parent state via LangGraph's annotation reducers.
The human-in-the-loop implementation in src/agents/shared/nodes/generate-post/human-node.ts is thorough. It constructs a rich HumanInterrupt object with the draft post, image options, scheduling date, and a markdown description with instructions. When the user responds, a separate LLM call in src/agents/shared/nodes/route-response.ts classifies the response as "rewrite post", "update date", "split URL", or "unknown" — then routes back into the graph accordingly. The routing itself uses Claude Sonnet with a Zod schema for structured output:
const routeSchema = z.object({
route: z.enum([
"rewrite_post",
"update_date",
"unknown_response",
"rewrite_with_split_url",
]),
});
const modelWithSchema = model.withStructuredOutput(routeSchema, {
name: "route",
});
The state definition in generate-post-state.ts uses LangGraph's Annotation.Root with custom reducers. Every field has an explicit reducer ((_state, update) => update) which means each node's output fully replaces the previous value — no accumulation, no merge conflicts. The configurable annotation layer handles runtime toggles like TEXT_ONLY_MODE and SKIP_USED_URLS_CHECK.
There is also a duplicate URL check via a LangGraph store. Before generating, checkIfUrlsArePreviouslyUsed queries saved URLs so you do not accidentally post about the same link twice. After the human approves, saveUsedUrls persists all links from the run.
Using it
The quickstart gets you running with four API keys (Anthropic, LangSmith, FireCrawl, Arcade):
git clone https://github.com/langchain-ai/social-media-agent.git
cd social-media-agent
yarn install
cp .env.quickstart.example .env
# fill in API keys
yarn langgraph:in_mem:up
yarn generate_post
The generate_post script sends a URL to the LangGraph server on port 54367. You review and approve posts through Agent Inbox at dev.agentinbox.ai. For automated ingestion, there is a cron system that pulls URLs from a Slack channel and feeds them through the pipeline daily.
The langgraph.json config registers 14 separate graphs — generate_post, curate_data, supervisor, repurposer, and others. This is not a single-agent toy. It is a multi-graph system with subgraph composition.
Rough edges
The dependency surface is heavy. You need Anthropic, Google Vertex AI (for YouTube), FireCrawl, Arcade, Supabase, Slack, Twitter developer credentials, and LinkedIn developer credentials for the full setup. The quickstart mode strips most of this away but also removes GitHub/Twitter/YouTube URL parsing and image uploads.
The prompts in src/agents/generate-post/prompts/index.ts are hardcoded for AI-focused content. The BUSINESS_CONTEXT prompt talks about LangChain products, agents, and multi-modal AI. You will need to rewrite these entirely for any other domain, and there is no configuration layer for it — just find-and-replace in the source.
Test coverage exists but is almost entirely integration tests (*.int.test.ts) that require live API keys. No unit tests for the graph logic itself, which makes it hard to contribute without setting up the full environment.
The repo is actively maintained — recent commits are from April 2026 — but they are mostly dependency bumps from Dependabot. The core logic has not seen major changes recently.
Bottom line
This is the most complete reference implementation I have seen for a LangGraph production agent. If you are building any multi-step AI pipeline with human approval gates, the patterns here — fan-out verification, interrupt-based HITL, LLM-powered response routing, duplicate detection via stores — are worth studying even if you never post a tweet.
