AI-assisted, multi-network social media posting for developers and creators.
Generate content with LLMs, review it as a human, and let a stealth browser agent publish it.
Core principle: cron generates → human reviews → agent posts (HITL by default).
Social Poster Agent (SPA) is a domain-agnostic social media automation stack for people who care about quality over spam. Give it a topic or a content brief, and it generates scroll-stopping posts for X, Threads, and more. Every draft goes through an LLM-as-a-Judge quality gate, A/B hook variants, content-style rotation, and near-duplicate detection before a human reviews it. Once approved, a queue worker drives Camoufox — a privacy-hardened Firefox fork — to publish the post exactly like a human would.
Everything that makes the content yours — brand voice, domain context, content pillars, humor mechanics, slop list, trending niches — lives in your markdown files and environment variables, not in the source code. The built-in fallback prompts are deliberately generic and use variables like {brandName}, {brandVoice}, and {domain} so the same codebase can write about developer tools, climate tech, finance, or any other topic without code changes.
No domain content is baked in. The repo ships with no vertical-specific sample data or prompts. CI even scans for residual vertical keywords to make sure a project's private domain does not leak into the open-source code. Your prompts and brand data stay in your local
.envpaths and gitignoredbrand-voice.md.
Most social schedulers are just queues with a text box. SPA treats posting as a pipeline:
- Source — topics from a sibling content repo (
content-agent-platform) or from an internal LLM-generated topic pool. - Generate — per-network drafts (X, Threads, and the platform roadmap below) with unique hooks, angles, and visual concepts.
- Judge — an LLM scores
anti_ai_tone,hook_strength,factual_accuracy, andcharacter_limit. - Refine — below-threshold drafts are rewritten automatically.
- Review — human approves, rejects, or edits in the UI.
- Post — a queue worker drives Camoufox to post like a human.
- Engage / measure — optional engagement and metrics modules (feature-flagged).
- Indie creators and founders who want a consistent social presence without sounding like a bot.
- Agencies managing multiple brands and networks from one dashboard.
- Developers who want an open, hackable automation stack with clean architecture and real browser automation.
- A multi-provider, free-first LLM router that switches to paid providers only when free ones fail.
- Per-network post generation with platform-specific character limits and tone.
- A human review queue with approve / reject / edit before anything goes live.
- A Camoufox-based browser worker that posts through the real platform UI.
- Docker Compose local stack, JWT auth, SSE live feed, and health monitoring.
This table is an operational support snapshot, not feature/task backlog status. Canonical work state is in
docs/planning/FEATURES.md.
| Platform | Type | Status | Notes |
|---|---|---|---|
| X (Twitter) | Social short-form | ✅ Ready | Tested and used daily. Auto-login + 2FA. Residential proxy strongly recommended for production. |
| Threads | Social short-form | ✅ Ready | Tested and used daily. Shared Instagram session pool with X. |
| Social short-form | Code exists, but real accounts and posting flow have not been battle-tested. Disabled by default (SOCIAL_FACEBOOK_ACTIVE=false). |
||
| Bluesky | Social short-form | 🔄 Needs validation | Poster exists, unit tests pass, not yet run against live Bluesky accounts. |
| Mastodon | Social short-form | 🔄 Needs validation | Poster exists, unit tests pass, not yet run against live instances. |
| Telegram | Channel/Broadcast | 🔄 Needs validation | API adapter exists for channel messages; UI posting flow not validated end-to-end. |
| Social + Articles | 🔄 Needs validation (social) / 🚧 In progress (articles) | Short-form social poster exists. Long-form article posting is under SYNDICATION_ENABLED and not finished. |
|
| Dev.to | Article syndication | 🚧 In progress | SYNDICATION_ENABLED=true. Poster exists, article flow not finished. |
| Hashnode | Article syndication | 🚧 In progress | SYNDICATION_ENABLED=true. Poster exists, article flow not finished. |
All posting is done through the real platform UI in a Camoufox browser, not through official APIs, to avoid rate limits and application reviews.
The architecture already supports these 14 platforms in SocialNetwork or in the syndication roadmap. The current focus is on making the short-form social network path rock-solid before expanding further.
| Phase | Platforms |
|---|---|
| 🟢 Now (battle-tested) | X, Threads |
| 🔄 Next (validate posters + selectors) | Facebook, Bluesky, Mastodon, Telegram, LinkedIn short-form |
| 🚧 Finish article syndication | Dev.to, Hashnode, LinkedIn long-form articles |
| 🧭 Planned | Medium, Substack, Reddit, Quora, Pinterest |
If you want a new platform, the cleanest path is to add a SocialNetwork enum value, a network-specific prompt in generation.graph.ts, and a poster under packages/backend/src/modules/posting/posters/.
- Backend: NestJS 11 + TypeScript, hexagonal ports/adapters, Prisma ORM
- Frontend: Vue 3 + Vite + Pinia + Tailwind CSS + Vue Router
- Shared:
@spa/shared— Zod schemas and domain types (single source of truth) - Queue: BullMQ on Redis (one queue per network, concurrency = 1)
- Database: PostgreSQL + Prisma
- Browser: Camoufox (Firefox fork) +
camoufox-js+playwright-core - LLMs: Multi-provider fallback chain — Groq, SambaNova, Cerebras, OpenRouter, DeepSeek, Anthropic, OpenAI, Google, NVIDIA, GitHub Models, Mistral, HuggingFace, Together, Cohere, Ollama
- Observability: Langfuse (prompt management + traces), Sentry, optional Discord alerts
- Infra: Docker Compose for PostgreSQL and Redis
Capability labels below describe the README snapshot, not canonical development status. Resolve current work by feature ID in
docs/planning/FEATURES.md.
| Feature | Status | Notes |
|---|---|---|
| Core pipeline | ||
| Multi-provider LLM fallback | ✅ Ready | Default gpt-5-nano (OpenAI) + llama-4-scout (Groq) + llama-4-maverick:free (OpenRouter). 15+ providers supported. |
| Topic generation | ✅ Ready | DB-backed pool, runs on a cron. Falls back to sibling content-agent-platform if CONTENT_AGENT_PLATFORM_PATH is set. |
| Per-network post generation | Ready (X/Threads) | X and Threads are battle-tested. Facebook, Bluesky, Mastodon, Telegram, and LinkedIn have posters and prompts but need real-world validation. |
| LLM-as-a-Judge quality gate | ✅ Ready | Scores tone, hook, facts, and length. Non-blocking. |
| Auto-refine on low scores | ✅ Ready | Rewrites drafts below the judge threshold. |
| A/B hook variants | ✅ Ready | Generates multiple scroll-stopping hooks per post. |
| Visual concept generation | ✅ Ready | Describes an image concept for each post. |
| SimHash near-duplicate detection | ✅ Ready | Skips posts with Hamming distance <= 3 vs last ~200 posts / 30 days. |
| Content style rotation | ✅ Ready | Cycles through defined brand voices/styles. |
| Slop lexicon + trend guardrail | ✅ Ready | Filters AI-sounding or off-trend content. |
| Human-in-the-loop review | ✅ Ready | UI dashboard for approve / reject / edit. Default is manual. |
| Queue-based posting | ✅ Ready | BullMQ, one worker per network, concurrency = 1, human-like delays. |
| Session management + auto-login | ✅ Ready | Encrypted storageState, auto-login, 2FA email code reader. |
| Rate limits | ✅ Ready | Per-network daily/weekly caps + minimum interval. |
| JWT cookie auth | ✅ Ready | Off by default (AUTH_ENABLED=false). Admin bootstrapped from env. |
| SSE live feed | ✅ Ready | Real-time updates to the UI without polling. |
| Content sources & distribution | ||
content-agent-platform filesystem reader |
✅ Ready | Reads sibling repo runs/brief-*, runs/topics-*. |
| DB-backed topic pool | ✅ Ready | Used when CONTENT_AGENT_PLATFORM_PATH is empty. |
| Content recycling | ✅ Ready | Re-runs top-performing old posts. RECYCLING_CRON_ENABLED=true. |
| Cross-platform syndication / article posting | 🚧 In progress | SYNDICATION_ENABLED=true. Dev.to, Hashnode, and LinkedIn long-form posters exist, but the full article generation + posting flow is not finished. |
| Canonical URL service | 🚧 In progress | Registered only when SYNDICATION_ENABLED=true. Used for cross-posted articles. |
| Automation modes | ||
| Cron-based scheduling | ✅ Ready | 11 independent cron services (generation, trending, recycling, health, etc.). |
| LangGraph orchestrator | 🧪 Experimental | ORCHESTRATOR_ENABLED=true. Single adaptive OBSERVE → DECIDE → EXECUTE → EVALUATE loop that can replace all crons. |
| Auto-approve | 🧪 Experimental | AUTO_APPROVE_ENABLED=true. Skips human review. Use with caution. |
| Autonomous runner | 🧪 Experimental | AUTONOMOUS_RUNNER_ENABLED=true. Runs full cycles without manual trigger. |
| Engagement | ||
| Engagement browser sessions | 🧪 Experimental | ENGAGEMENT_ENABLED=true. Like, comment, quote, repost via human-behavior engine. |
| Replies monitoring | 🧪 Experimental | REPLIES_ENABLED=true. Requires ENGAGEMENT_ENABLED=true. |
| Media & enhancements | ||
| Quote cards | 🧪 Experimental | QUOTE_CARDS_ENABLED=true. Generates styled quote images. |
| Image rendering | ✅ Ready | SVG-to-PNG via satori + resvg. Used by quote cards and visual concepts. |
| Infrastructure / ops | ||
| Multi-instance safety | ✅ Ready | Distributed locks + per-instance heartbeats on Redis. |
| Proxy rotation | 🧪 Experimental | PROXY_ROTATION_ENABLED=true. Residential/mobile proxy rotation. |
| Captcha solver | 🧪 Experimental | CAPTCHA_SOLVER_ENABLED=true. 2Captcha integration. |
| Metrics scraping | 🧪 Experimental | METRICS_SCRAPER_ENABLED=true. Collects engagement numbers from platforms. |
| Discord alerts | ✅ Ready | DLQ, health, and captcha notifications. |
| Health monitoring + reconciliation | ✅ Ready | Hourly checks + stuck-post recovery. |
| Flow control (pause/resume/killswitch) | ✅ Ready | Redis-backed pause flags for generation, posting, engagement, replies. |
| IndexNow pings | ✅ Ready | Notifies search engines on new syndicated articles. |
- ✅ Ready — implemented, has tests, works in CI, and is either enabled by default or can be enabled with a single env var.
- 🧪 Experimental — implemented behind a feature flag and may need real-network testing, external services, or further hardening before production use.
- 🚧 In progress — code exists, but the end-to-end flow is not complete or not yet tested with real accounts.
- 🧭 Planned — product intent exists; canonical status and tasks are resolved by
feature ID in
docs/planning/FEATURES.mdanddocs/planning/BACKLOG.md.
# 1. Install dependencies
corepack enable
pnpm install
# 2. Start PostgreSQL + Redis
cp .env.example .env
pnpm infra:up
# 3. Configure the app
cp brand-voice.example.md brand-voice.md
# edit .env with your social credentials and LLM keys
# 4. Run migrations
pnpm prisma:migrate
# 5. Start backend + UI
pnpm dev:all| Endpoint | URL |
|---|---|
| REST API | http://localhost:3100/api/v1 |
| Swagger / OpenAPI | http://localhost:3100/docs |
| UI dashboard | http://localhost:3101 |
# Safe dry-run: opens a real browser, types a real post, but intercepts the final submit.
pnpm dry-runThe live command is intentionally separate and requires a confirmation prompt.
All feature flags are in .env.example with sensible defaults. The most important toggles:
| Variable | Default | Effect |
|---|---|---|
AUTH_ENABLED |
false |
🔐 JWT cookie auth for the UI. |
ORCHESTRATOR_ENABLED |
false |
🧪 Use the LangGraph orchestrator instead of crons. |
ENGAGEMENT_ENABLED |
false |
💬 Enable browser engagement (likes, comments, etc.). |
REPLIES_ENABLED |
false |
💬 Enable reply monitoring (requires ENGAGEMENT_ENABLED). |
QUOTE_CARDS_ENABLED |
false |
🧪 Enable quote-card image generation. |
SYNDICATION_ENABLED |
false |
🚧 Enable article syndication to Dev.to, Hashnode, and LinkedIn long-form articles. Not finished. |
AUTO_APPROVE_ENABLED |
false |
|
AUTONOMOUS_RUNNER_ENABLED |
false |
|
PROXY_ROTATION_ENABLED |
false |
🛡️ Rotate residential/mobile proxies per network. |
CAPTCHA_SOLVER_ENABLED |
false |
🛡️ Use 2Captcha when Camoufox hits a captcha. |
METRICS_SCRAPER_ENABLED |
false |
📊 Collect engagement metrics daily. |
Brand voice, domain context, trending niches, and visual styles can be customized via .env paths or by editing the example markdown files.
- Hexagonal ports/adapters — domain ports (
ILlmPort,IBrowserPort,IContentPort, etc.) are DI tokens. Swap an adapter by changing a single module binding. - LangGraph generation pipeline — one graph run per topic fans out to per-network parallel branches:
research_extract → hook_generation → angle → draft → critique → refine → visual_concept → ab_variant → human_review → save. - LangGraph orchestrator (optional) —
OBSERVE → DECIDE → EXECUTE → EVALUATEloop with Redis checkpoints, crash-resume, and adaptive sleep. - Human-in-the-loop — generation can
interrupt()for review and resume withCommand({ resume: ... }). - Free-first LLM routing — tries free providers first, falls back to paid only on failure.
- Reasoning-model aware —
gpt-5-*,o1,o3, ando4-miniskiptemperatureautomatically. - Browser hardening — Camoufox + memory-optimized
firefox_user_prefs, resource blocking in read-only contexts, and persistent Facebook profiles.
For the full operational guide, see CLAUDE.md. For contribution guidelines, see CONTRIBUTING.md.
Product sequencing lives in ROADMAP_V2.md; canonical feature/task status and the
completed-work archive live in docs/planning/. Agent
quality/evaluation design starts at docs/evaluation/.
Check the documentation map before creating another
feature proposal, roadmap, backlog or implementation plan.
Dependency waves and the task-claiming method are in the
execution roadmap; the current queue remains in
docs/planning/BACKLOG.md.
pnpm dev # backend only
pnpm dev:ui # UI only
pnpm dev:all # both
pnpm build # build all packages
pnpm lint # oxlint
pnpm format # oxfmt
pnpm test # backend vitest
pnpm test:unit # backend unit + UI tests
pnpm test:integration # integration tests
pnpm test:system # system tests
pnpm test:acceptance # acceptance tests
pnpm test:e2e # backend e2e
pnpm test:ui-e2e # UI e2e
pnpm prisma:migrate # run Prisma migrations
pnpm prisma:studio # open Prisma Studio
pnpm infra:up # start PostgreSQL + Redis
pnpm infra:down # stop PostgreSQL + Rediscd packages/backend
npx tsc --noEmit
pnpm lint
pnpm test:unitThe test suite is layered:
- Unit — isolated services and utilities.
- Integration — top-down, bottom-up, sandwich, big-bang module wiring.
- System — full graph and posting slices.
- Acceptance — BDD scenarios and ATP test cases.
- E2E — full flows with mocked browser where possible.
Note: Browser automation is mocked in automated tests. Green CI does not guarantee working posting. Always validate with
pnpm dry-runbefore enabling live posting.
- 🐦 Multi-network content generation for X and Threads.
- 👤 Human-in-the-loop review and queue-based posting.
- 🧠 Multi-provider free-first LLM fallback.
- 🔄 Topic pool management and content recycling.
- 🔐 Session encryption, auto-login, and 2FA via email.
- ❤️ Health monitoring, rate limiting, and flow control.
These features are implemented and pass tests, but have not been fully exercised with real accounts:
- 🦋 Bluesky, Mastodon, Telegram, and LinkedIn short-form — posters and prompts exist, live selectors need validation.
⚠️ Facebook — code exists but has not been battle-tested; session churn is the main open question.- 🧪 Orchestrator — the adaptive LangGraph loop is implemented but should be monitored for 24-48 hours before replacing crons.
- 💬 Engagement / replies — ~1300 lines of code, frozen behind
ENGAGEMENT_ENABLED. Needs real-network soak testing. - 🤖 Auto-approve / autonomous runner — functional, but by design these bypass human review and can post accidentally.
- 📊 Metrics scraper — depends on platform HTML selectors that change frequently.
- 🛡️ Captcha solver / proxy rotation — require third-party accounts and careful production tuning.
- 📝 Article generation and syndication — Dev.to, Hashnode, and LinkedIn long-form posters exist, but the full flow from article outline → draft → published post is not complete.
- ⏰ Remove remaining
@Crondecorators once the orchestrator is stable. - 🌐 More networks: LinkedIn, Bluesky, Mastodon, Telegram, Medium, Substack, Reddit, Quora, Pinterest.
- 📘 Better Facebook session recovery.
- ⚖️ LLM judge calibration UI and feedback loop.
See .forge/orchestrator/MASTER-PLAN.md for historical design detail; its task
checklist is frozen. Current status is ORCH-001/ORCH-101..102 in
docs/planning/.
social-poster-agent/
├── packages/
│ ├── shared/ # @spa/shared — Zod schemas, domain types
│ ├── backend/ # @spa/backend — NestJS REST API + Prisma + BullMQ
│ └── ui/ # @spa/ui — Vue 3 + Vite + Pinia
├── docker/ # Production Dockerfiles + docker-compose.prod.yml
├── infra/ # Local PostgreSQL :5433 + Redis :6381
├── brand-voice.example.md
├── .env.example
├── CONTRIBUTING.md
├── CLAUDE.md
└── pnpm-workspace.yaml
Social Poster Agent is released under the Apache License 2.0.
Contributions, bug reports, and ideas are welcome. Please read CONTRIBUTING.md for the PR process, coding conventions, and verification steps. If you are hacking on something experimental, check CLAUDE.md first — it documents the non-obvious traps and architectural decisions.